clientmap.cpp 24 KB

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