LCOV - code coverage report
Current view: top level - src - clientmap.cpp (source / functions) Hit Total Coverage
Test: report Lines: 391 421 92.9 %
Date: 2015-07-11 18:23:49 Functions: 19 23 82.6 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "clientmap.h"
      21             : #include "client.h"
      22             : #include "mapblock_mesh.h"
      23             : #include <IMaterialRenderer.h>
      24             : #include <matrix4.h>
      25             : #include "log.h"
      26             : #include "mapsector.h"
      27             : #include "nodedef.h"
      28             : #include "mapblock.h"
      29             : #include "profiler.h"
      30             : #include "settings.h"
      31             : #include "camera.h"               // CameraModes
      32             : #include "util/mathconstants.h"
      33             : #include <algorithm>
      34             : 
      35             : #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
      36             : 
      37           1 : ClientMap::ClientMap(
      38             :                 Client *client,
      39             :                 IGameDef *gamedef,
      40             :                 MapDrawControl &control,
      41             :                 scene::ISceneNode* parent,
      42             :                 scene::ISceneManager* mgr,
      43             :                 s32 id
      44             : ):
      45             :         Map(dout_client, gamedef),
      46             :         scene::ISceneNode(parent, mgr, id),
      47             :         m_client(client),
      48             :         m_control(control),
      49             :         m_camera_position(0,0,0),
      50             :         m_camera_direction(0,0,1),
      51           1 :         m_camera_fov(M_PI)
      52             : {
      53           2 :         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
      54           1 :                         BS*1000000,BS*1000000,BS*1000000);
      55             : 
      56             :         /* TODO: Add a callback function so these can be updated when a setting
      57             :          *       changes.  At this point in time it doesn't matter (e.g. /set
      58             :          *       is documented to change server settings only)
      59             :          *
      60             :          * TODO: Local caching of settings is not optimal and should at some stage
      61             :          *       be updated to use a global settings object for getting thse values
      62             :          *       (as opposed to the this local caching). This can be addressed in
      63             :          *       a later release.
      64             :          */
      65           1 :         m_cache_trilinear_filter  = g_settings->getBool("trilinear_filter");
      66           1 :         m_cache_bilinear_filter   = g_settings->getBool("bilinear_filter");
      67           1 :         m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter");
      68             : 
      69           1 : }
      70             : 
      71           2 : ClientMap::~ClientMap()
      72             : {
      73             :         /*JMutexAutoLock lock(mesh_mutex);
      74             : 
      75             :         if(mesh != NULL)
      76             :         {
      77             :                 mesh->drop();
      78             :                 mesh = NULL;
      79             :         }*/
      80           2 : }
      81             : 
      82         786 : MapSector * ClientMap::emergeSector(v2s16 p2d)
      83             : {
      84        1572 :         DSTACK(__FUNCTION_NAME);
      85             :         // Check that it doesn't exist already
      86             :         try{
      87        1030 :                 return getSectorNoGenerate(p2d);
      88             :         }
      89         244 :         catch(InvalidPositionException &e)
      90             :         {
      91             :         }
      92             : 
      93             :         // Create a sector
      94         244 :         ClientMapSector *sector = new ClientMapSector(this, p2d, m_gamedef);
      95             : 
      96             :         {
      97             :                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
      98         244 :                 m_sectors[p2d] = sector;
      99             :         }
     100             : 
     101         244 :         return sector;
     102             : }
     103             : 
     104        1166 : void ClientMap::OnRegisterSceneNode()
     105             : {
     106        1166 :         if(IsVisible)
     107             :         {
     108        1166 :                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
     109        1166 :                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
     110             :         }
     111             : 
     112        1166 :         ISceneNode::OnRegisterSceneNode();
     113        1166 : }
     114             : 
     115       82897 : static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
     116             :                 float start_off, float end_off, u32 needed_count, INodeDefManager *nodemgr)
     117             : {
     118       82897 :         float d0 = (float)BS * p0.getDistanceFrom(p1);
     119       82897 :         v3s16 u0 = p1 - p0;
     120       82897 :         v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
     121       82897 :         uf.normalize();
     122       82897 :         v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
     123       82897 :         u32 count = 0;
     124      606930 :         for(float s=start_off; s<d0+end_off; s+=step){
     125      591509 :                 v3f pf = p0f + uf * s;
     126      591509 :                 v3s16 p = floatToInt(pf, BS);
     127      591509 :                 MapNode n = map->getNodeNoEx(p);
     128      591509 :                 bool is_transparent = false;
     129      591509 :                 const ContentFeatures &f = nodemgr->get(n);
     130      591509 :                 if(f.solidness == 0)
     131      448843 :                         is_transparent = (f.visual_solidness != 2);
     132             :                 else
     133      142666 :                         is_transparent = (f.solidness != 2);
     134      591509 :                 if(!is_transparent){
     135      138562 :                         if(count == needed_count)
     136       67476 :                                 return true;
     137       71086 :                         count++;
     138             :                 }
     139      524033 :                 step *= stepfac;
     140             :         }
     141       15421 :         return false;
     142             : }
     143             : 
     144         179 : void ClientMap::updateDrawList(video::IVideoDriver* driver)
     145             : {
     146         358 :         ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
     147         179 :         g_profiler->add("CM::updateDrawList() count", 1);
     148             : 
     149         179 :         INodeDefManager *nodemgr = m_gamedef->ndef();
     150             : 
     151       46276 :         for(std::map<v3s16, MapBlock*>::iterator
     152         179 :                         i = m_drawlist.begin();
     153       30970 :                         i != m_drawlist.end(); ++i)
     154             :         {
     155       15306 :                 MapBlock *block = i->second;
     156       15306 :                 block->refDrop();
     157             :         }
     158         179 :         m_drawlist.clear();
     159             : 
     160         179 :         m_camera_mutex.Lock();
     161         179 :         v3f camera_position = m_camera_position;
     162         179 :         v3f camera_direction = m_camera_direction;
     163         179 :         f32 camera_fov = m_camera_fov;
     164             :         //v3s16 camera_offset = m_camera_offset;
     165         179 :         m_camera_mutex.Unlock();
     166             : 
     167             :         // Use a higher fov to accomodate faster camera movements.
     168             :         // Blocks are cropped better when they are drawn.
     169             :         // Or maybe they aren't? Well whatever.
     170         179 :         camera_fov *= 1.2;
     171             : 
     172         179 :         v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
     173         179 :         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
     174         179 :         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
     175         179 :         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
     176             :         // Take a fair amount as we will be dropping more out later
     177             :         // Umm... these additions are a bit strange but they are needed.
     178             :         v3s16 p_blocks_min(
     179         179 :                         p_nodes_min.X / MAP_BLOCKSIZE - 3,
     180         179 :                         p_nodes_min.Y / MAP_BLOCKSIZE - 3,
     181         537 :                         p_nodes_min.Z / MAP_BLOCKSIZE - 3);
     182             :         v3s16 p_blocks_max(
     183         179 :                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
     184         179 :                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
     185         537 :                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
     186             : 
     187             :         // Number of blocks in rendering range
     188         179 :         u32 blocks_in_range = 0;
     189             :         // Number of blocks occlusion culled
     190         179 :         u32 blocks_occlusion_culled = 0;
     191             :         // Number of blocks in rendering range but don't have a mesh
     192         179 :         u32 blocks_in_range_without_mesh = 0;
     193             :         // Blocks that had mesh that would have been drawn according to
     194             :         // rendering range (if max blocks limit didn't kick in)
     195         179 :         u32 blocks_would_have_drawn = 0;
     196             :         // Blocks that were drawn and had a mesh
     197         179 :         u32 blocks_drawn = 0;
     198             :         // Blocks which had a corresponding meshbuffer for this pass
     199             :         //u32 blocks_had_pass_meshbuf = 0;
     200             :         // Blocks from which stuff was actually drawn
     201             :         //u32 blocks_without_stuff = 0;
     202             :         // Distance to farthest drawn block
     203         179 :         float farthest_drawn = 0;
     204             : 
     205       64132 :         for(std::map<v2s16, MapSector*>::iterator
     206         179 :                         si = m_sectors.begin();
     207       42874 :                         si != m_sectors.end(); ++si)
     208             :         {
     209       21258 :                 MapSector *sector = si->second;
     210       21258 :                 v2s16 sp = sector->getPos();
     211             : 
     212       21258 :                 if(m_control.range_all == false)
     213             :                 {
     214       21258 :                         if(sp.X < p_blocks_min.X
     215       21220 :                         || sp.X > p_blocks_max.X
     216       21220 :                         || sp.Y < p_blocks_min.Z
     217       21220 :                         || sp.Y > p_blocks_max.Z)
     218          58 :                                 continue;
     219             :                 }
     220             : 
     221       42400 :                 MapBlockVect sectorblocks;
     222       21200 :                 sector->getBlocks(sectorblocks);
     223             : 
     224             :                 /*
     225             :                         Loop through blocks in sector
     226             :                 */
     227             : 
     228       21200 :                 u32 sector_blocks_drawn = 0;
     229             : 
     230      252948 :                 for(MapBlockVect::iterator i = sectorblocks.begin();
     231      168632 :                                 i != sectorblocks.end(); i++)
     232             :                 {
     233       63116 :                         MapBlock *block = *i;
     234             : 
     235             :                         /*
     236             :                                 Compare block position to camera position, skip
     237             :                                 if not seen on display
     238             :                         */
     239             : 
     240       63116 :                         if (block->mesh != NULL)
     241       55109 :                                 block->mesh->updateCameraOffset(m_camera_offset);
     242             : 
     243       63116 :                         float range = 100000 * BS;
     244       63116 :                         if(m_control.range_all == false)
     245       63116 :                                 range = m_control.wanted_range * BS;
     246             : 
     247       63116 :                         float d = 0.0;
     248       63116 :                         if(isBlockInSight(block->getPos(), camera_position,
     249             :                                         camera_direction, camera_fov,
     250             :                                         range, &d) == false)
     251             :                         {
     252       84867 :                                 continue;
     253             :                         }
     254             : 
     255             :                         // This is ugly (spherical distance limit?)
     256             :                         /*if(m_control.range_all == false &&
     257             :                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
     258             :                                 continue;*/
     259             : 
     260       25944 :                         blocks_in_range++;
     261             : 
     262             :                         /*
     263             :                                 Ignore if mesh doesn't exist
     264             :                         */
     265             :                         {
     266             :                                 //JMutexAutoLock lock(block->mesh_mutex);
     267             : 
     268       25944 :                                 if(block->mesh == NULL){
     269        4297 :                                         blocks_in_range_without_mesh++;
     270        4297 :                                         continue;
     271             :                                 }
     272             :                         }
     273             : 
     274             :                         /*
     275             :                                 Occlusion culling
     276             :                         */
     277             : 
     278             :                         // No occlusion culling when free_move is on and camera is
     279             :                         // inside ground
     280       21647 :                         bool occlusion_culling_enabled = true;
     281       21647 :                         if(g_settings->getBool("free_move")){
     282           0 :                                 MapNode n = getNodeNoEx(cam_pos_nodes);
     283           0 :                                 if(n.getContent() == CONTENT_IGNORE ||
     284           0 :                                                 nodemgr->get(n).solidness == 2)
     285           0 :                                         occlusion_culling_enabled = false;
     286             :                         }
     287             : 
     288       21647 :                         v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
     289       21647 :                         cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);
     290       21647 :                         float step = BS*1;
     291       21647 :                         float stepfac = 1.1;
     292       21647 :                         float startoff = BS*1;
     293       21647 :                         float endoff = -BS*MAP_BLOCKSIZE*1.42*1.42;
     294       21647 :                         v3s16 spn = cam_pos_nodes + v3s16(0,0,0);
     295       21647 :                         s16 bs2 = MAP_BLOCKSIZE/2 + 1;
     296       21647 :                         u32 needed_count = 1;
     297       43294 :                         if(
     298       64941 :                                 occlusion_culling_enabled &&
     299      108235 :                                 isOccluded(this, spn, cpn + v3s16(0,0,0),
     300       37716 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     301       59363 :                                 isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
     302       24381 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     303       46028 :                                 isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
     304       21669 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     305       43316 :                                 isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
     306       21639 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     307       43286 :                                 isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
     308       21630 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     309       43277 :                                 isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
     310       19353 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     311       41000 :                                 isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
     312       18684 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     313       40331 :                                 isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
     314       40325 :                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
     315       40325 :                                 isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
     316             :                                         step, stepfac, startoff, endoff, needed_count, nodemgr)
     317             :                         )
     318             :                         {
     319        6226 :                                 blocks_occlusion_culled++;
     320        6226 :                                 continue;
     321             :                         }
     322             : 
     323             :                         // This block is in range. Reset usage timer.
     324       15421 :                         block->resetUsageTimer();
     325             : 
     326             :                         // Limit block count in case of a sudden increase
     327       15421 :                         blocks_would_have_drawn++;
     328       15421 :                         if(blocks_drawn >= m_control.wanted_max_blocks
     329           0 :                                         && m_control.range_all == false
     330           0 :                                         && d > m_control.wanted_min_range * BS)
     331           0 :                                 continue;
     332             : 
     333             :                         // Add to set
     334       15421 :                         block->refGrab();
     335       15421 :                         m_drawlist[block->getPos()] = block;
     336             : 
     337       15421 :                         sector_blocks_drawn++;
     338       15421 :                         blocks_drawn++;
     339       15421 :                         if(d/BS > farthest_drawn)
     340         514 :                                 farthest_drawn = d/BS;
     341             : 
     342             :                 } // foreach sectorblocks
     343             : 
     344       21200 :                 if(sector_blocks_drawn != 0)
     345        6794 :                         m_last_drawn_sectors.insert(sp);
     346             :         }
     347             : 
     348         179 :         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
     349         179 :         m_control.blocks_drawn = blocks_drawn;
     350         179 :         m_control.farthest_drawn = farthest_drawn;
     351             : 
     352         179 :         g_profiler->avg("CM: blocks in range", blocks_in_range);
     353         179 :         g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
     354         179 :         if(blocks_in_range != 0)
     355         358 :                 g_profiler->avg("CM: blocks in range without mesh (frac)",
     356         179 :                                 (float)blocks_in_range_without_mesh/blocks_in_range);
     357         179 :         g_profiler->avg("CM: blocks drawn", blocks_drawn);
     358         179 :         g_profiler->avg("CM: farthest drawn", farthest_drawn);
     359         179 :         g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
     360         179 : }
     361             : 
     362     1793840 : struct MeshBufList
     363             : {
     364             :         video::SMaterial m;
     365             :         std::vector<scene::IMeshBuffer*> bufs;
     366             : };
     367             : 
     368        4664 : struct MeshBufListList
     369             : {
     370             :         std::vector<MeshBufList> lists;
     371             : 
     372             :         void clear()
     373             :         {
     374             :                 lists.clear();
     375             :         }
     376             : 
     377     1426358 :         void add(scene::IMeshBuffer *buf)
     378             :         {
     379   292121316 :                 for(std::vector<MeshBufList>::iterator i = lists.begin();
     380   194747544 :                                 i != lists.end(); ++i){
     381    97109079 :                         MeshBufList &l = *i;
     382    97109079 :                         video::SMaterial &m = buf->getMaterial();
     383             : 
     384             :                         // comparing a full material is quite expensive so we don't do it if
     385             :                         // not even first texture is equal
     386    97109079 :                         if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
     387    95914357 :                                 continue;
     388             : 
     389     1194722 :                         if (l.m == m) {
     390     1161665 :                                 l.bufs.push_back(buf);
     391     2323330 :                                 return;
     392             :                         }
     393             :                 }
     394      529386 :                 MeshBufList l;
     395      264693 :                 l.m = buf->getMaterial();
     396      264693 :                 l.bufs.push_back(buf);
     397      264693 :                 lists.push_back(l);
     398             :         }
     399             : };
     400             : 
     401        2332 : void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
     402             : {
     403        4664 :         DSTACK(__FUNCTION_NAME);
     404             : 
     405        2332 :         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
     406             : 
     407        4664 :         std::string prefix;
     408        2332 :         if(pass == scene::ESNRP_SOLID)
     409        1166 :                 prefix = "CM: solid: ";
     410             :         else
     411        1166 :                 prefix = "CM: transparent: ";
     412             : 
     413             :         /*
     414             :                 This is called two times per frame, reset on the non-transparent one
     415             :         */
     416        2332 :         if(pass == scene::ESNRP_SOLID)
     417             :         {
     418        1166 :                 m_last_drawn_sectors.clear();
     419             :         }
     420             : 
     421             :         /*
     422             :                 Get time for measuring timeout.
     423             : 
     424             :                 Measuring time is very useful for long delays when the
     425             :                 machine is swapping a lot.
     426             :         */
     427        2332 :         int time1 = time(0);
     428             : 
     429             :         /*
     430             :                 Get animation parameters
     431             :         */
     432        2332 :         float animation_time = m_client->getAnimationTime();
     433        2332 :         int crack = m_client->getCrackLevel();
     434        2332 :         u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
     435             : 
     436        2332 :         m_camera_mutex.Lock();
     437        2332 :         v3f camera_position = m_camera_position;
     438        2332 :         v3f camera_direction = m_camera_direction;
     439        2332 :         f32 camera_fov = m_camera_fov;
     440        2332 :         m_camera_mutex.Unlock();
     441             : 
     442             :         /*
     443             :                 Get all blocks and draw all visible ones
     444             :         */
     445             : 
     446        2332 :         v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
     447             : 
     448        2332 :         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
     449             : 
     450        2332 :         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
     451        2332 :         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
     452             : 
     453             :         // Take a fair amount as we will be dropping more out later
     454             :         // Umm... these additions are a bit strange but they are needed.
     455             :         v3s16 p_blocks_min(
     456        2332 :                         p_nodes_min.X / MAP_BLOCKSIZE - 3,
     457        2332 :                         p_nodes_min.Y / MAP_BLOCKSIZE - 3,
     458        6996 :                         p_nodes_min.Z / MAP_BLOCKSIZE - 3);
     459             :         v3s16 p_blocks_max(
     460        2332 :                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
     461        2332 :                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
     462        6996 :                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
     463             : 
     464        2332 :         u32 vertex_count = 0;
     465        2332 :         u32 meshbuffer_count = 0;
     466             : 
     467             :         // For limiting number of mesh animations per frame
     468        2332 :         u32 mesh_animate_count = 0;
     469        2332 :         u32 mesh_animate_count_far = 0;
     470             : 
     471             :         // Blocks that were drawn and had a mesh
     472        2332 :         u32 blocks_drawn = 0;
     473             :         // Blocks which had a corresponding meshbuffer for this pass
     474        2332 :         u32 blocks_had_pass_meshbuf = 0;
     475             :         // Blocks from which stuff was actually drawn
     476        2332 :         u32 blocks_without_stuff = 0;
     477             : 
     478             :         /*
     479             :                 Draw the selected MapBlocks
     480             :         */
     481             : 
     482             :         {
     483        4664 :         ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);
     484             : 
     485        4664 :         MeshBufListList drawbufs;
     486             : 
     487      536354 :         for(std::map<v3s16, MapBlock*>::iterator
     488        2332 :                         i = m_drawlist.begin();
     489      359124 :                         i != m_drawlist.end(); ++i)
     490             :         {
     491      177230 :                 MapBlock *block = i->second;
     492             : 
     493             :                 // If the mesh of the block happened to get deleted, ignore it
     494      177230 :                 if(block->mesh == NULL)
     495       24552 :                         continue;
     496             : 
     497      177230 :                 float d = 0.0;
     498      177230 :                 if(isBlockInSight(block->getPos(), camera_position,
     499             :                                 camera_direction, camera_fov,
     500             :                                 100000*BS, &d) == false)
     501             :                 {
     502       24552 :                         continue;
     503             :                 }
     504             : 
     505             :                 // Mesh animation
     506             :                 {
     507             :                         //JMutexAutoLock lock(block->mesh_mutex);
     508      152678 :                         MapBlockMesh *mapBlockMesh = block->mesh;
     509             :                         assert(mapBlockMesh);
     510             :                         // Pretty random but this should work somewhat nicely
     511      152678 :                         bool faraway = d >= BS*50;
     512             :                         //bool faraway = d >= m_control.wanted_range * BS;
     513      456787 :                         if(mapBlockMesh->isAnimationForced() ||
     514      231567 :                                         !faraway ||
     515       78889 :                                         mesh_animate_count_far < (m_control.range_all ? 200 : 50))
     516             :                         {
     517      148401 :                                 bool animated = mapBlockMesh->animate(
     518             :                                                 faraway,
     519             :                                                 animation_time,
     520             :                                                 crack,
     521      148401 :                                                 daynight_ratio);
     522      148401 :                                 if(animated)
     523       73112 :                                         mesh_animate_count++;
     524      148401 :                                 if(animated && faraway)
     525       31236 :                                         mesh_animate_count_far++;
     526             :                         }
     527             :                         else
     528             :                         {
     529        4277 :                                 mapBlockMesh->decreaseAnimationForceTimer();
     530             :                         }
     531             :                 }
     532             : 
     533             :                 /*
     534             :                         Get the meshbuffers of the block
     535             :                 */
     536             :                 {
     537             :                         //JMutexAutoLock lock(block->mesh_mutex);
     538             : 
     539      152678 :                         MapBlockMesh *mapBlockMesh = block->mesh;
     540             :                         assert(mapBlockMesh);
     541             : 
     542      152678 :                         scene::IMesh *mesh = mapBlockMesh->getMesh();
     543             :                         assert(mesh);
     544             : 
     545      152678 :                         u32 c = mesh->getMeshBufferCount();
     546     3005394 :                         for(u32 i=0; i<c; i++)
     547             :                         {
     548     2852716 :                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
     549             : 
     550     2852716 :                                 buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, m_cache_trilinear_filter);
     551     2852716 :                                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, m_cache_bilinear_filter);
     552     2852716 :                                 buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, m_cache_anistropic_filter);
     553             : 
     554     2852716 :                                 const video::SMaterial& material = buf->getMaterial();
     555             :                                 video::IMaterialRenderer* rnd =
     556     2852716 :                                                 driver->getMaterialRenderer(material.MaterialType);
     557     2852716 :                                 bool transparent = (rnd && rnd->isTransparent());
     558     2852716 :                                 if(transparent == is_transparent_pass)
     559             :                                 {
     560     1426358 :                                         if(buf->getVertexCount() == 0)
     561           0 :                                                 errorstream<<"Block ["<<analyze_block(block)
     562           0 :                                                                 <<"] contains an empty meshbuf"<<std::endl;
     563     1426358 :                                         drawbufs.add(buf);
     564             :                                 }
     565             :                         }
     566             :                 }
     567             :         }
     568             : 
     569        2332 :         std::vector<MeshBufList> &lists = drawbufs.lists;
     570             : 
     571        2332 :         int timecheck_counter = 0;
     572      801075 :         for(std::vector<MeshBufList>::iterator i = lists.begin();
     573      534050 :                         i != lists.end(); ++i) {
     574      264693 :                 timecheck_counter++;
     575      264693 :                 if(timecheck_counter > 50) {
     576        4343 :                         timecheck_counter = 0;
     577        4343 :                         int time2 = time(0);
     578        4343 :                         if(time2 > time1 + 4) {
     579             :                                 infostream << "ClientMap::renderMap(): "
     580           0 :                                         "Rendering takes ages, returning."
     581           0 :                                         << std::endl;
     582           0 :                                 return;
     583             :                         }
     584             :                 }
     585             : 
     586      264693 :                 MeshBufList &list = *i;
     587             : 
     588      264693 :                 driver->setMaterial(list.m);
     589             : 
     590     5073153 :                 for(std::vector<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
     591     3382102 :                                 j != list.bufs.end(); ++j) {
     592     1426358 :                         scene::IMeshBuffer *buf = *j;
     593     1426358 :                         driver->drawMeshBuffer(buf);
     594     1426358 :                         vertex_count += buf->getVertexCount();
     595     1426358 :                         meshbuffer_count++;
     596             :                 }
     597             : 
     598             :         }
     599             :         } // ScopeProfiler
     600             : 
     601             :         // Log only on solid pass because values are the same
     602        2332 :         if(pass == scene::ESNRP_SOLID){
     603        1166 :                 g_profiler->avg("CM: animated meshes", mesh_animate_count);
     604        1166 :                 g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
     605             :         }
     606             : 
     607        2332 :         g_profiler->avg(prefix+"vertices drawn", vertex_count);
     608        2332 :         if(blocks_had_pass_meshbuf != 0)
     609           0 :                 g_profiler->avg(prefix+"meshbuffers per block",
     610           0 :                                 (float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
     611        2332 :         if(blocks_drawn != 0)
     612           0 :                 g_profiler->avg(prefix+"empty blocks (frac)",
     613           0 :                                 (float)blocks_without_stuff / blocks_drawn);
     614             : 
     615             :         /*infostream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
     616             :                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
     617             : }
     618             : 
     619       53120 : static bool getVisibleBrightness(Map *map, v3f p0, v3f dir, float step,
     620             :                 float step_multiplier, float start_distance, float end_distance,
     621             :                 INodeDefManager *ndef, u32 daylight_factor, float sunlight_min_d,
     622             :                 int *result, bool *sunlight_seen)
     623             : {
     624       53120 :         int brightness_sum = 0;
     625       53120 :         int brightness_count = 0;
     626       53120 :         float distance = start_distance;
     627       53120 :         dir.normalize();
     628       53120 :         v3f pf = p0;
     629       53120 :         pf += dir * distance;
     630       53120 :         int noncount = 0;
     631       53120 :         bool nonlight_seen = false;
     632       53120 :         bool allow_allowing_non_sunlight_propagates = false;
     633       53120 :         bool allow_non_sunlight_propagates = false;
     634             :         // Check content nearly at camera position
     635             :         {
     636       53120 :                 v3s16 p = floatToInt(p0 /*+ dir * 3*BS*/, BS);
     637       53120 :                 MapNode n = map->getNodeNoEx(p);
     638      106240 :                 if(ndef->get(n).param_type == CPT_LIGHT &&
     639       53120 :                                 !ndef->get(n).sunlight_propagates)
     640           0 :                         allow_allowing_non_sunlight_propagates = true;
     641             :         }
     642             :         // If would start at CONTENT_IGNORE, start closer
     643             :         {
     644       53120 :                 v3s16 p = floatToInt(pf, BS);
     645       53120 :                 MapNode n = map->getNodeNoEx(p);
     646       53120 :                 if(n.getContent() == CONTENT_IGNORE){
     647        4920 :                         float newd = 2*BS;
     648        4920 :                         pf = p0 + dir * 2*newd;
     649        4920 :                         distance = newd;
     650        4920 :                         sunlight_min_d = 0;
     651             :                 }
     652             :         }
     653      366554 :         for(int i=0; distance < end_distance; i++){
     654      351159 :                 pf += dir * step;
     655      351159 :                 distance += step;
     656      351159 :                 step *= step_multiplier;
     657             : 
     658      351159 :                 v3s16 p = floatToInt(pf, BS);
     659      351159 :                 MapNode n = map->getNodeNoEx(p);
     660      351159 :                 if(allow_allowing_non_sunlight_propagates && i == 0 &&
     661      351159 :                                 ndef->get(n).param_type == CPT_LIGHT &&
     662           0 :                                 !ndef->get(n).sunlight_propagates){
     663           0 :                         allow_non_sunlight_propagates = true;
     664             :                 }
     665      709793 :                 if(ndef->get(n).param_type != CPT_LIGHT ||
     666      195696 :                                 (!ndef->get(n).sunlight_propagates &&
     667        7475 :                                         !allow_non_sunlight_propagates)){
     668      170413 :                         nonlight_seen = true;
     669      170413 :                         noncount++;
     670      170413 :                         if(noncount >= 4)
     671       37725 :                                 break;
     672      132688 :                         continue;
     673             :                 }
     674      180746 :                 if(distance >= sunlight_min_d && *sunlight_seen == false
     675       57963 :                                 && nonlight_seen == false)
     676       32283 :                         if(n.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
     677       20205 :                                 *sunlight_seen = true;
     678      180746 :                 noncount = 0;
     679      180746 :                 brightness_sum += decode_light(n.getLightBlend(daylight_factor, ndef));
     680      180746 :                 brightness_count++;
     681             :         }
     682       53120 :         *result = 0;
     683       53120 :         if(brightness_count == 0)
     684       25032 :                 return false;
     685       28088 :         *result = brightness_sum / brightness_count;
     686             :         /*std::cerr<<"Sampled "<<brightness_count<<" points; result="
     687             :                         <<(*result)<<std::endl;*/
     688       28088 :         return true;
     689             : }
     690             : 
     691        1166 : int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
     692             :                 int oldvalue, bool *sunlight_seen_result)
     693             : {
     694        1166 :         const bool debugprint = false;
     695        1166 :         INodeDefManager *ndef = m_gamedef->ndef();
     696             :         static v3f z_directions[50] = {
     697             :                 v3f(-100, 0, 0)
     698        1166 :         };
     699             :         static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = {
     700             :                 -1000,
     701             :         };
     702        1166 :         if(z_directions[0].X < -99){
     703          51 :                 for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
     704         150 :                         z_directions[i] = v3f(
     705          50 :                                 0.01 * myrand_range(-100, 100),
     706             :                                 1.0,
     707          50 :                                 0.01 * myrand_range(-100, 100)
     708          50 :                         );
     709          50 :                         z_offsets[i] = 0.01 * myrand_range(0,100);
     710             :                 }
     711             :         }
     712             :         if(debugprint)
     713             :                 std::cerr<<"In goes "<<PP(m_camera_direction)<<", out comes ";
     714        1166 :         int sunlight_seen_count = 0;
     715        1166 :         float sunlight_min_d = max_d*0.8;
     716        1166 :         if(sunlight_min_d > 35*BS)
     717        1133 :                 sunlight_min_d = 35*BS;
     718        2332 :         std::vector<int> values;
     719       53671 :         for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
     720       53120 :                 v3f z_dir = z_directions[i];
     721       53120 :                 z_dir.normalize();
     722       53120 :                 core::CMatrix4<f32> a;
     723       53120 :                 a.buildRotateFromTo(v3f(0,1,0), z_dir);
     724       53120 :                 v3f dir = m_camera_direction;
     725       53120 :                 a.rotateVect(dir);
     726       53120 :                 int br = 0;
     727       53120 :                 float step = BS*1.5;
     728       53120 :                 if(max_d > 35*BS)
     729       52420 :                         step = max_d / 35 * 1.5;
     730       53120 :                 float off = step * z_offsets[i];
     731       53120 :                 bool sunlight_seen_now = false;
     732      106240 :                 bool ok = getVisibleBrightness(this, m_camera_position, dir,
     733       53120 :                                 step, 1.0, max_d*0.6+off, max_d, ndef, daylight_factor,
     734             :                                 sunlight_min_d,
     735       53120 :                                 &br, &sunlight_seen_now);
     736       53120 :                 if(sunlight_seen_now)
     737       20205 :                         sunlight_seen_count++;
     738       53120 :                 if(!ok)
     739       25032 :                         continue;
     740       28088 :                 values.push_back(br);
     741             :                 // Don't try too much if being in the sun is clear
     742       28088 :                 if(sunlight_seen_count >= 20)
     743         615 :                         break;
     744             :         }
     745        1166 :         int brightness_sum = 0;
     746        1166 :         int brightness_count = 0;
     747        1166 :         std::sort(values.begin(), values.end());
     748        1166 :         u32 num_values_to_use = values.size();
     749        1166 :         if(num_values_to_use >= 10)
     750        1150 :                 num_values_to_use -= num_values_to_use/2;
     751          16 :         else if(num_values_to_use >= 7)
     752           3 :                 num_values_to_use -= num_values_to_use/3;
     753        1166 :         u32 first_value_i = (values.size() - num_values_to_use) / 2;
     754             :         if(debugprint){
     755             :                 for(u32 i=0; i < first_value_i; i++)
     756             :                         std::cerr<<values[i]<<" ";
     757             :                 std::cerr<<"[";
     758             :         }
     759       15514 :         for(u32 i=first_value_i; i < first_value_i+num_values_to_use; i++){
     760             :                 if(debugprint)
     761             :                         std::cerr<<values[i]<<" ";
     762       14348 :                 brightness_sum += values[i];
     763       14348 :                 brightness_count++;
     764             :         }
     765             :         if(debugprint){
     766             :                 std::cerr<<"]";
     767             :                 for(u32 i=first_value_i+num_values_to_use; i < values.size(); i++)
     768             :                         std::cerr<<values[i]<<" ";
     769             :         }
     770        1166 :         int ret = 0;
     771        1166 :         if(brightness_count == 0){
     772           0 :                 MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS));
     773           0 :                 if(ndef->get(n).param_type == CPT_LIGHT){
     774           0 :                         ret = decode_light(n.getLightBlend(daylight_factor, ndef));
     775             :                 } else {
     776           0 :                         ret = oldvalue;
     777             :                 }
     778             :         } else {
     779             :                 /*float pre = (float)brightness_sum / (float)brightness_count;
     780             :                 float tmp = pre;
     781             :                 const float d = 0.2;
     782             :                 pre *= 1.0 + d*2;
     783             :                 pre -= tmp * d;
     784             :                 int preint = pre;
     785             :                 ret = MYMAX(0, MYMIN(255, preint));*/
     786        1166 :                 ret = brightness_sum / brightness_count;
     787             :         }
     788             :         if(debugprint)
     789             :                 std::cerr<<"Result: "<<ret<<" sunlight_seen_count="
     790             :                                 <<sunlight_seen_count<<std::endl;
     791        1166 :         *sunlight_seen_result = (sunlight_seen_count > 0);
     792        2332 :         return ret;
     793             : }
     794             : 
     795        1166 : void ClientMap::renderPostFx(CameraMode cam_mode)
     796             : {
     797        1166 :         INodeDefManager *nodemgr = m_gamedef->ndef();
     798             : 
     799             :         // Sadly ISceneManager has no "post effects" render pass, in that case we
     800             :         // could just register for that and handle it in renderMap().
     801             : 
     802        1166 :         m_camera_mutex.Lock();
     803        1166 :         v3f camera_position = m_camera_position;
     804        1166 :         m_camera_mutex.Unlock();
     805             : 
     806        1166 :         MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
     807             : 
     808             :         // - If the player is in a solid node, make everything black.
     809             :         // - If the player is in liquid, draw a semi-transparent overlay.
     810             :         // - Do not if player is in third person mode
     811        1166 :         const ContentFeatures& features = nodemgr->get(n);
     812        1166 :         video::SColor post_effect_color = features.post_effect_color;
     813        3498 :         if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
     814        3498 :                         m_gamedef->checkLocalPrivilege("noclip")) &&
     815             :                         cam_mode == CAMERA_MODE_FIRST)
     816             :         {
     817           0 :                 post_effect_color = video::SColor(255, 0, 0, 0);
     818             :         }
     819        1166 :         if (post_effect_color.getAlpha() != 0)
     820             :         {
     821             :                 // Draw a full-screen rectangle
     822           0 :                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
     823           0 :                 v2u32 ss = driver->getScreenSize();
     824           0 :                 core::rect<s32> rect(0,0, ss.X, ss.Y);
     825           0 :                 driver->draw2DRectangle(post_effect_color, rect);
     826             :         }
     827        1166 : }
     828             : 
     829           0 : void ClientMap::PrintInfo(std::ostream &out)
     830             : {
     831           0 :         out<<"ClientMap: ";
     832           3 : }
     833             : 
     834             : 

Generated by: LCOV version 1.11