Noise: Prevent unittest crash caused by division by zero
[oweals/minetest.git] / src / clientmap.cpp
index fb70a97e92f04ef58ab7845c498d4d396ce2dd9a..7027d07e42ba0f7ed3a9a73758d3ade3de9f179e 100644 (file)
@@ -31,16 +31,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "camera.h"               // CameraModes
 #include "util/basic_macros.h"
 #include <algorithm>
+#include "client/renderingengine.h"
 
 ClientMap::ClientMap(
                Client *client,
                MapDrawControl &control,
-               scene::ISceneNode* parent,
-               scene::ISceneManager* mgr,
                s32 id
 ):
        Map(dout_client, client),
-       scene::ISceneNode(parent, mgr, id),
+       scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
+               RenderingEngine::get_scene_manager(), id),
        m_client(client),
        m_control(control),
        m_camera_position(0,0,0),
@@ -67,13 +67,6 @@ ClientMap::ClientMap(
 
 ClientMap::~ClientMap()
 {
-       /*MutexAutoLock lock(mesh_mutex);
-
-       if(mesh != NULL)
-       {
-               mesh->drop();
-               mesh = NULL;
-       }*/
 }
 
 MapSector * ClientMap::emergeSector(v2s16 p2d)
@@ -109,35 +102,6 @@ void ClientMap::OnRegisterSceneNode()
        ISceneNode::OnRegisterSceneNode();
 }
 
-static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
-               float start_off, float end_off, u32 needed_count, INodeDefManager *nodemgr)
-{
-       float d0 = (float)BS * p0.getDistanceFrom(p1);
-       v3s16 u0 = p1 - p0;
-       v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
-       uf.normalize();
-       v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
-       u32 count = 0;
-       for(float s=start_off; s<d0+end_off; s+=step){
-               v3f pf = p0f + uf * s;
-               v3s16 p = floatToInt(pf, BS);
-               MapNode n = map->getNodeNoEx(p);
-               bool is_transparent = false;
-               const ContentFeatures &f = nodemgr->get(n);
-               if(f.solidness == 0)
-                       is_transparent = (f.visual_solidness != 2);
-               else
-                       is_transparent = (f.solidness != 2);
-               if(!is_transparent){
-                       count++;
-                       if(count >= needed_count)
-                               return true;
-               }
-               step *= stepfac;
-       }
-       return false;
-}
-
 void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
                v3s16 *p_blocks_min, v3s16 *p_blocks_max)
 {
@@ -248,11 +212,11 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                                if not seen on display
                        */
 
-                       if (block->mesh != NULL)
+                       if (block->mesh)
                                block->mesh->updateCameraOffset(m_camera_offset);
 
                        float range = 100000 * BS;
-                       if (m_control.range_all == false)
+                       if (!m_control.range_all)
                                range = m_control.wanted_range * BS;
 
                        float d = 0.0;
@@ -265,7 +229,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                        /*
                                Ignore if mesh doesn't exist
                        */
-                       if (block->mesh == NULL) {
+                       if (!block->mesh) {
                                blocks_in_range_without_mesh++;
                                continue;
                        }
@@ -273,43 +237,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                        /*
                                Occlusion culling
                        */
-                       v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
-                       cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
-                       float step = BS * 1;
-                       float stepfac = 1.1;
-                       float startoff = BS * 1;
-                       // The occlusion search of 'isOccluded()' must stop short of the target
-                       // point by distance 'endoff' (end offset) to not enter the target mapblock.
-                       // For the 8 mapblock corners 'endoff' must therefore be the maximum diagonal
-                       // of a mapblock, because we must consider all view angles.
-                       // sqrt(1^2 + 1^2 + 1^2) = 1.732
-                       float endoff = -BS * MAP_BLOCKSIZE * 1.732050807569;
-                       v3s16 spn = cam_pos_nodes;
-                       s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
-                       // to reduce the likelihood of falsely occluded blocks
-                       // require at least two solid blocks
-                       // this is a HACK, we should think of a more precise algorithm
-                       u32 needed_count = 2;
-                       if (occlusion_culling_enabled &&
-                                       // For the central point of the mapblock 'endoff' can be halved
-                                       isOccluded(this, spn, cpn,
-                                               step, stepfac, startoff, endoff / 2.0f, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef) &&
-                                       isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
-                                               step, stepfac, startoff, endoff, needed_count, m_nodedef)) {
+                       if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) {
                                blocks_occlusion_culled++;
                                continue;
                        }
@@ -361,20 +289,25 @@ struct MeshBufList
 
 struct MeshBufListList
 {
-       std::vector<MeshBufList> lists;
+       /*!
+        * 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()
        {
-               lists.clear();
+               for (int l = 0; l < MAX_TILE_LAYERS; l++)
+                       lists[l].clear();
        }
 
-       void add(scene::IMeshBuffer *buf)
+       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(std::vector<MeshBufList>::iterator i = lists.begin();
-                               i != lists.end(); ++i){
-                       MeshBufList &l = *i;
-
+               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)
@@ -388,7 +321,7 @@ struct MeshBufListList
                MeshBufList l;
                l.m = m;
                l.bufs.push_back(buf);
-               lists.push_back(l);
+               list.push_back(l);
        }
 };
 
@@ -416,7 +349,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                Measuring time is very useful for long delays when the
                machine is swapping a lot.
        */
-       int time1 = time(0);
+       std::time_t time1 = time(0);
 
        /*
                Get animation parameters
@@ -461,7 +394,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                MapBlock *block = i->second;
 
                // If the mesh of the block happened to get deleted, ignore it
-               if (block->mesh == NULL)
+               if (!block->mesh)
                        continue;
 
                float d = 0.0;
@@ -499,63 +432,65 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                        MapBlockMesh *mapBlockMesh = block->mesh;
                        assert(mapBlockMesh);
 
-                       scene::IMesh *mesh = mapBlockMesh->getMesh();
-                       assert(mesh);
+                       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);
+                               u32 c = mesh->getMeshBufferCount();
+                               for (u32 i = 0; i < c; i++) {
+                                       scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
 
-                               video::SMaterial& material = buf->getMaterial();
-                               video::IMaterialRenderer* rnd =
+                                       video::SMaterial& material = buf->getMaterial();
+                                       video::IMaterialRenderer* rnd =
                                                driver->getMaterialRenderer(material.MaterialType);
-                               bool transparent = (rnd && rnd->isTransparent());
-                               if (transparent == is_transparent_pass) {
-                                       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);
+                                       bool transparent = (rnd && rnd->isTransparent());
+                                       if (transparent == is_transparent_pass) {
+                                               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);
+                                       }
                                }
                        }
                }
        }
 
-       std::vector<MeshBufList> &lists = drawbufs.lists;
-
-       int timecheck_counter = 0;
-       for (std::vector<MeshBufList>::iterator i = lists.begin();
-                       i != lists.end(); ++i) {
-               timecheck_counter++;
-               if (timecheck_counter > 50) {
-                       timecheck_counter = 0;
-                       int time2 = time(0);
-                       if (time2 > time1 + 4) {
-                               infostream << "ClientMap::renderMap(): "
-                                       "Rendering takes ages, returning."
-                                       << std::endl;
-                               return;
+       // Render all layers in order
+       for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+               std::vector<MeshBufList> &lists = drawbufs.lists[layer];
+
+               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;
+                               }
                        }
-               }
-
-               MeshBufList &list = *i;
 
-               driver->setMaterial(list.m);
+                       driver->setMaterial(list.m);
 
-               for (std::vector<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
-                               j != list.bufs.end(); ++j) {
-                       scene::IMeshBuffer *buf = *j;
-                       driver->drawMeshBuffer(buf);
-                       vertex_count += buf->getVertexCount();
-                       meshbuffer_count++;
+                       for (scene::IMeshBuffer *buf : list.bufs) {
+                               driver->drawMeshBuffer(buf);
+                               vertex_count += buf->getVertexCount();
+                               meshbuffer_count++;
+                       }
                }
-
        }
        } // ScopeProfiler