clientmap.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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 "mapsector.h"
  22. #include "mapblock.h"
  23. #include "profiler.h"
  24. #include "settings.h"
  25. #include "camera.h" // CameraModes
  26. #include "util/basic_macros.h"
  27. #include <algorithm>
  28. #include "client/renderingengine.h"
  29. ClientMap::ClientMap(
  30. Client *client,
  31. MapDrawControl &control,
  32. s32 id
  33. ):
  34. Map(dout_client, client),
  35. scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
  36. RenderingEngine::get_scene_manager(), id),
  37. m_client(client),
  38. m_control(control)
  39. {
  40. m_box = aabb3f(-BS*1000000,-BS*1000000,-BS*1000000,
  41. BS*1000000,BS*1000000,BS*1000000);
  42. /* TODO: Add a callback function so these can be updated when a setting
  43. * changes. At this point in time it doesn't matter (e.g. /set
  44. * is documented to change server settings only)
  45. *
  46. * TODO: Local caching of settings is not optimal and should at some stage
  47. * be updated to use a global settings object for getting thse values
  48. * (as opposed to the this local caching). This can be addressed in
  49. * a later release.
  50. */
  51. m_cache_trilinear_filter = g_settings->getBool("trilinear_filter");
  52. m_cache_bilinear_filter = g_settings->getBool("bilinear_filter");
  53. m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter");
  54. }
  55. MapSector * ClientMap::emergeSector(v2s16 p2d)
  56. {
  57. DSTACK(FUNCTION_NAME);
  58. // Check that it doesn't exist already
  59. try {
  60. return getSectorNoGenerate(p2d);
  61. } catch(InvalidPositionException &e) {
  62. }
  63. // Create a sector
  64. MapSector *sector = new MapSector(this, p2d, m_gamedef);
  65. m_sectors[p2d] = sector;
  66. return sector;
  67. }
  68. void ClientMap::OnRegisterSceneNode()
  69. {
  70. if(IsVisible)
  71. {
  72. SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
  73. SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
  74. }
  75. ISceneNode::OnRegisterSceneNode();
  76. }
  77. void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
  78. v3s16 *p_blocks_min, v3s16 *p_blocks_max)
  79. {
  80. v3s16 box_nodes_d = m_control.wanted_range * v3s16(1, 1, 1);
  81. // Define p_nodes_min/max as v3s32 because 'cam_pos_nodes -/+ box_nodes_d'
  82. // can exceed the range of v3s16 when a large view range is used near the
  83. // world edges.
  84. v3s32 p_nodes_min(
  85. cam_pos_nodes.X - box_nodes_d.X,
  86. cam_pos_nodes.Y - box_nodes_d.Y,
  87. cam_pos_nodes.Z - box_nodes_d.Z);
  88. v3s32 p_nodes_max(
  89. cam_pos_nodes.X + box_nodes_d.X,
  90. cam_pos_nodes.Y + box_nodes_d.Y,
  91. cam_pos_nodes.Z + box_nodes_d.Z);
  92. // Take a fair amount as we will be dropping more out later
  93. // Umm... these additions are a bit strange but they are needed.
  94. *p_blocks_min = v3s16(
  95. p_nodes_min.X / MAP_BLOCKSIZE - 3,
  96. p_nodes_min.Y / MAP_BLOCKSIZE - 3,
  97. p_nodes_min.Z / MAP_BLOCKSIZE - 3);
  98. *p_blocks_max = v3s16(
  99. p_nodes_max.X / MAP_BLOCKSIZE + 1,
  100. p_nodes_max.Y / MAP_BLOCKSIZE + 1,
  101. p_nodes_max.Z / MAP_BLOCKSIZE + 1);
  102. }
  103. void ClientMap::updateDrawList()
  104. {
  105. ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
  106. g_profiler->add("CM::updateDrawList() count", 1);
  107. for (auto &i : m_drawlist) {
  108. MapBlock *block = i.second;
  109. block->refDrop();
  110. }
  111. m_drawlist.clear();
  112. v3f camera_position = m_camera_position;
  113. v3f camera_direction = m_camera_direction;
  114. f32 camera_fov = m_camera_fov;
  115. // Use a higher fov to accomodate faster camera movements.
  116. // Blocks are cropped better when they are drawn.
  117. // Or maybe they aren't? Well whatever.
  118. camera_fov *= 1.2;
  119. v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
  120. v3s16 p_blocks_min;
  121. v3s16 p_blocks_max;
  122. getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
  123. // Number of blocks in rendering range
  124. u32 blocks_in_range = 0;
  125. // Number of blocks occlusion culled
  126. u32 blocks_occlusion_culled = 0;
  127. // Number of blocks in rendering range but don't have a mesh
  128. u32 blocks_in_range_without_mesh = 0;
  129. // Blocks that had mesh that would have been drawn according to
  130. // rendering range (if max blocks limit didn't kick in)
  131. u32 blocks_would_have_drawn = 0;
  132. // Blocks that were drawn and had a mesh
  133. u32 blocks_drawn = 0;
  134. // Blocks which had a corresponding meshbuffer for this pass
  135. //u32 blocks_had_pass_meshbuf = 0;
  136. // Blocks from which stuff was actually drawn
  137. //u32 blocks_without_stuff = 0;
  138. // Distance to farthest drawn block
  139. float farthest_drawn = 0;
  140. // No occlusion culling when free_move is on and camera is
  141. // inside ground
  142. bool occlusion_culling_enabled = true;
  143. if (g_settings->getBool("free_move")) {
  144. MapNode n = getNodeNoEx(cam_pos_nodes);
  145. if (n.getContent() == CONTENT_IGNORE ||
  146. m_nodedef->get(n).solidness == 2)
  147. occlusion_culling_enabled = false;
  148. }
  149. for (const auto &sector_it : m_sectors) {
  150. MapSector *sector = sector_it.second;
  151. v2s16 sp = sector->getPos();
  152. if (!m_control.range_all) {
  153. if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X ||
  154. sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z)
  155. continue;
  156. }
  157. MapBlockVect sectorblocks;
  158. sector->getBlocks(sectorblocks);
  159. /*
  160. Loop through blocks in sector
  161. */
  162. u32 sector_blocks_drawn = 0;
  163. for (auto block : sectorblocks) {
  164. /*
  165. Compare block position to camera position, skip
  166. if not seen on display
  167. */
  168. if (block->mesh)
  169. block->mesh->updateCameraOffset(m_camera_offset);
  170. float range = 100000 * BS;
  171. if (!m_control.range_all)
  172. range = m_control.wanted_range * BS;
  173. float d = 0.0;
  174. if (!isBlockInSight(block->getPos(), camera_position,
  175. camera_direction, camera_fov, range, &d))
  176. continue;
  177. blocks_in_range++;
  178. /*
  179. Ignore if mesh doesn't exist
  180. */
  181. if (!block->mesh) {
  182. blocks_in_range_without_mesh++;
  183. continue;
  184. }
  185. /*
  186. Occlusion culling
  187. */
  188. if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) {
  189. blocks_occlusion_culled++;
  190. continue;
  191. }
  192. // This block is in range. Reset usage timer.
  193. block->resetUsageTimer();
  194. // Limit block count in case of a sudden increase
  195. blocks_would_have_drawn++;
  196. if (blocks_drawn >= m_control.wanted_max_blocks &&
  197. !m_control.range_all &&
  198. d > m_control.wanted_range * BS)
  199. continue;
  200. // Add to set
  201. block->refGrab();
  202. m_drawlist[block->getPos()] = block;
  203. sector_blocks_drawn++;
  204. blocks_drawn++;
  205. if (d / BS > farthest_drawn)
  206. farthest_drawn = d / BS;
  207. } // foreach sectorblocks
  208. if (sector_blocks_drawn != 0)
  209. m_last_drawn_sectors.insert(sp);
  210. }
  211. g_profiler->avg("CM: blocks in range", blocks_in_range);
  212. g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
  213. if (blocks_in_range != 0)
  214. g_profiler->avg("CM: blocks in range without mesh (frac)",
  215. (float)blocks_in_range_without_mesh / blocks_in_range);
  216. g_profiler->avg("CM: blocks drawn", blocks_drawn);
  217. g_profiler->avg("CM: farthest drawn", farthest_drawn);
  218. g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
  219. }
  220. struct MeshBufList
  221. {
  222. video::SMaterial m;
  223. std::vector<scene::IMeshBuffer*> bufs;
  224. };
  225. struct MeshBufListList
  226. {
  227. /*!
  228. * Stores the mesh buffers of the world.
  229. * The array index is the material's layer.
  230. * The vector part groups vertices by material.
  231. */
  232. std::vector<MeshBufList> lists[MAX_TILE_LAYERS];
  233. void clear()
  234. {
  235. for (auto &list : lists)
  236. list.clear();
  237. }
  238. void add(scene::IMeshBuffer *buf, u8 layer)
  239. {
  240. // Append to the correct layer
  241. std::vector<MeshBufList> &list = lists[layer];
  242. const video::SMaterial &m = buf->getMaterial();
  243. for (MeshBufList &l : list) {
  244. // comparing a full material is quite expensive so we don't do it if
  245. // not even first texture is equal
  246. if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
  247. continue;
  248. if (l.m == m) {
  249. l.bufs.push_back(buf);
  250. return;
  251. }
  252. }
  253. MeshBufList l;
  254. l.m = m;
  255. l.bufs.push_back(buf);
  256. list.push_back(l);
  257. }
  258. };
  259. void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
  260. {
  261. DSTACK(FUNCTION_NAME);
  262. bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
  263. std::string prefix;
  264. if (pass == scene::ESNRP_SOLID)
  265. prefix = "CM: solid: ";
  266. else
  267. prefix = "CM: transparent: ";
  268. /*
  269. This is called two times per frame, reset on the non-transparent one
  270. */
  271. if (pass == scene::ESNRP_SOLID)
  272. m_last_drawn_sectors.clear();
  273. /*
  274. Get time for measuring timeout.
  275. Measuring time is very useful for long delays when the
  276. machine is swapping a lot.
  277. */
  278. std::time_t time1 = time(0);
  279. /*
  280. Get animation parameters
  281. */
  282. float animation_time = m_client->getAnimationTime();
  283. int crack = m_client->getCrackLevel();
  284. u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
  285. v3f camera_position = m_camera_position;
  286. v3f camera_direction = m_camera_direction;
  287. f32 camera_fov = m_camera_fov;
  288. /*
  289. Get all blocks and draw all visible ones
  290. */
  291. u32 vertex_count = 0;
  292. u32 meshbuffer_count = 0;
  293. // For limiting number of mesh animations per frame
  294. u32 mesh_animate_count = 0;
  295. u32 mesh_animate_count_far = 0;
  296. // Blocks that were drawn and had a mesh
  297. u32 blocks_drawn = 0;
  298. // Blocks which had a corresponding meshbuffer for this pass
  299. u32 blocks_had_pass_meshbuf = 0;
  300. // Blocks from which stuff was actually drawn
  301. u32 blocks_without_stuff = 0;
  302. /*
  303. Draw the selected MapBlocks
  304. */
  305. {
  306. ScopeProfiler sp(g_profiler, prefix + "drawing blocks", SPT_AVG);
  307. MeshBufListList drawbufs;
  308. for (auto &i : m_drawlist) {
  309. MapBlock *block = i.second;
  310. // If the mesh of the block happened to get deleted, ignore it
  311. if (!block->mesh)
  312. continue;
  313. float d = 0.0;
  314. if (!isBlockInSight(block->getPos(), camera_position,
  315. camera_direction, camera_fov, 100000 * BS, &d))
  316. continue;
  317. // Mesh animation
  318. if (pass == scene::ESNRP_SOLID) {
  319. //MutexAutoLock lock(block->mesh_mutex);
  320. MapBlockMesh *mapBlockMesh = block->mesh;
  321. assert(mapBlockMesh);
  322. // Pretty random but this should work somewhat nicely
  323. bool faraway = d >= BS * 50;
  324. //bool faraway = d >= m_control.wanted_range * BS;
  325. if (mapBlockMesh->isAnimationForced() || !faraway ||
  326. mesh_animate_count_far < (m_control.range_all ? 200 : 50)) {
  327. bool animated = mapBlockMesh->animate(faraway, animation_time,
  328. crack, daynight_ratio);
  329. if (animated)
  330. mesh_animate_count++;
  331. if (animated && faraway)
  332. mesh_animate_count_far++;
  333. } else {
  334. mapBlockMesh->decreaseAnimationForceTimer();
  335. }
  336. }
  337. /*
  338. Get the meshbuffers of the block
  339. */
  340. {
  341. //MutexAutoLock lock(block->mesh_mutex);
  342. MapBlockMesh *mapBlockMesh = block->mesh;
  343. assert(mapBlockMesh);
  344. for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
  345. scene::IMesh *mesh = mapBlockMesh->getMesh(layer);
  346. assert(mesh);
  347. u32 c = mesh->getMeshBufferCount();
  348. for (u32 i = 0; i < c; i++) {
  349. scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
  350. video::SMaterial& material = buf->getMaterial();
  351. video::IMaterialRenderer* rnd =
  352. driver->getMaterialRenderer(material.MaterialType);
  353. bool transparent = (rnd && rnd->isTransparent());
  354. if (transparent == is_transparent_pass) {
  355. if (buf->getVertexCount() == 0)
  356. errorstream << "Block [" << analyze_block(block)
  357. << "] contains an empty meshbuf" << std::endl;
  358. material.setFlag(video::EMF_TRILINEAR_FILTER,
  359. m_cache_trilinear_filter);
  360. material.setFlag(video::EMF_BILINEAR_FILTER,
  361. m_cache_bilinear_filter);
  362. material.setFlag(video::EMF_ANISOTROPIC_FILTER,
  363. m_cache_anistropic_filter);
  364. material.setFlag(video::EMF_WIREFRAME,
  365. m_control.show_wireframe);
  366. drawbufs.add(buf, layer);
  367. }
  368. }
  369. }
  370. }
  371. }
  372. // Render all layers in order
  373. for (auto &lists : drawbufs.lists) {
  374. int timecheck_counter = 0;
  375. for (MeshBufList &list : lists) {
  376. timecheck_counter++;
  377. if (timecheck_counter > 50) {
  378. timecheck_counter = 0;
  379. std::time_t time2 = time(0);
  380. if (time2 > time1 + 4) {
  381. infostream << "ClientMap::renderMap(): "
  382. "Rendering takes ages, returning."
  383. << std::endl;
  384. return;
  385. }
  386. }
  387. driver->setMaterial(list.m);
  388. for (scene::IMeshBuffer *buf : list.bufs) {
  389. driver->drawMeshBuffer(buf);
  390. vertex_count += buf->getVertexCount();
  391. meshbuffer_count++;
  392. }
  393. }
  394. }
  395. } // ScopeProfiler
  396. // Log only on solid pass because values are the same
  397. if (pass == scene::ESNRP_SOLID) {
  398. g_profiler->avg("CM: animated meshes", mesh_animate_count);
  399. g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
  400. }
  401. g_profiler->avg(prefix + "vertices drawn", vertex_count);
  402. if (blocks_had_pass_meshbuf != 0)
  403. g_profiler->avg(prefix + "meshbuffers per block",
  404. (float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
  405. if (blocks_drawn != 0)
  406. g_profiler->avg(prefix + "empty blocks (frac)",
  407. (float)blocks_without_stuff / blocks_drawn);
  408. }
  409. static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
  410. float step_multiplier, float start_distance, float end_distance,
  411. INodeDefManager *ndef, u32 daylight_factor, float sunlight_min_d,
  412. int *result, bool *sunlight_seen)
  413. {
  414. int brightness_sum = 0;
  415. int brightness_count = 0;
  416. float distance = start_distance;
  417. dir.normalize();
  418. v3f pf = p0;
  419. pf += dir * distance;
  420. int noncount = 0;
  421. bool nonlight_seen = false;
  422. bool allow_allowing_non_sunlight_propagates = false;
  423. bool allow_non_sunlight_propagates = false;
  424. // Check content nearly at camera position
  425. {
  426. v3s16 p = floatToInt(p0 /*+ dir * 3*BS*/, BS);
  427. MapNode n = map->getNodeNoEx(p);
  428. if(ndef->get(n).param_type == CPT_LIGHT &&
  429. !ndef->get(n).sunlight_propagates)
  430. allow_allowing_non_sunlight_propagates = true;
  431. }
  432. // If would start at CONTENT_IGNORE, start closer
  433. {
  434. v3s16 p = floatToInt(pf, BS);
  435. MapNode n = map->getNodeNoEx(p);
  436. if(n.getContent() == CONTENT_IGNORE){
  437. float newd = 2*BS;
  438. pf = p0 + dir * 2*newd;
  439. distance = newd;
  440. sunlight_min_d = 0;
  441. }
  442. }
  443. for (int i=0; distance < end_distance; i++) {
  444. pf += dir * step;
  445. distance += step;
  446. step *= step_multiplier;
  447. v3s16 p = floatToInt(pf, BS);
  448. MapNode n = map->getNodeNoEx(p);
  449. if (allow_allowing_non_sunlight_propagates && i == 0 &&
  450. ndef->get(n).param_type == CPT_LIGHT &&
  451. !ndef->get(n).sunlight_propagates) {
  452. allow_non_sunlight_propagates = true;
  453. }
  454. if (ndef->get(n).param_type != CPT_LIGHT ||
  455. (!ndef->get(n).sunlight_propagates &&
  456. !allow_non_sunlight_propagates)){
  457. nonlight_seen = true;
  458. noncount++;
  459. if(noncount >= 4)
  460. break;
  461. continue;
  462. }
  463. if (distance >= sunlight_min_d && !*sunlight_seen && !nonlight_seen)
  464. if (n.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
  465. *sunlight_seen = true;
  466. noncount = 0;
  467. brightness_sum += decode_light(n.getLightBlend(daylight_factor, ndef));
  468. brightness_count++;
  469. }
  470. *result = 0;
  471. if(brightness_count == 0)
  472. return false;
  473. *result = brightness_sum / brightness_count;
  474. /*std::cerr<<"Sampled "<<brightness_count<<" points; result="
  475. <<(*result)<<std::endl;*/
  476. return true;
  477. }
  478. int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
  479. int oldvalue, bool *sunlight_seen_result)
  480. {
  481. static v3f z_directions[50] = {
  482. v3f(-100, 0, 0)
  483. };
  484. static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = {
  485. -1000,
  486. };
  487. if(z_directions[0].X < -99){
  488. for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
  489. // Assumes FOV of 72 and 16/9 aspect ratio
  490. z_directions[i] = v3f(
  491. 0.02 * myrand_range(-100, 100),
  492. 1.0,
  493. 0.01 * myrand_range(-100, 100)
  494. ).normalize();
  495. z_offsets[i] = 0.01 * myrand_range(0,100);
  496. }
  497. }
  498. int sunlight_seen_count = 0;
  499. float sunlight_min_d = max_d*0.8;
  500. if(sunlight_min_d > 35*BS)
  501. sunlight_min_d = 35*BS;
  502. std::vector<int> values;
  503. for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
  504. v3f z_dir = z_directions[i];
  505. core::CMatrix4<f32> a;
  506. a.buildRotateFromTo(v3f(0,1,0), z_dir);
  507. v3f dir = m_camera_direction;
  508. a.rotateVect(dir);
  509. int br = 0;
  510. float step = BS*1.5;
  511. if(max_d > 35*BS)
  512. step = max_d / 35 * 1.5;
  513. float off = step * z_offsets[i];
  514. bool sunlight_seen_now = false;
  515. bool ok = getVisibleBrightness(this, m_camera_position, dir,
  516. step, 1.0, max_d*0.6+off, max_d, m_nodedef, daylight_factor,
  517. sunlight_min_d,
  518. &br, &sunlight_seen_now);
  519. if(sunlight_seen_now)
  520. sunlight_seen_count++;
  521. if(!ok)
  522. continue;
  523. values.push_back(br);
  524. // Don't try too much if being in the sun is clear
  525. if(sunlight_seen_count >= 20)
  526. break;
  527. }
  528. int brightness_sum = 0;
  529. int brightness_count = 0;
  530. std::sort(values.begin(), values.end());
  531. u32 num_values_to_use = values.size();
  532. if(num_values_to_use >= 10)
  533. num_values_to_use -= num_values_to_use/2;
  534. else if(num_values_to_use >= 7)
  535. num_values_to_use -= num_values_to_use/3;
  536. u32 first_value_i = (values.size() - num_values_to_use) / 2;
  537. for (u32 i=first_value_i; i < first_value_i + num_values_to_use; i++) {
  538. brightness_sum += values[i];
  539. brightness_count++;
  540. }
  541. int ret = 0;
  542. if(brightness_count == 0){
  543. MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS));
  544. if(m_nodedef->get(n).param_type == CPT_LIGHT){
  545. ret = decode_light(n.getLightBlend(daylight_factor, m_nodedef));
  546. } else {
  547. ret = oldvalue;
  548. }
  549. } else {
  550. ret = brightness_sum / brightness_count;
  551. }
  552. *sunlight_seen_result = (sunlight_seen_count > 0);
  553. return ret;
  554. }
  555. void ClientMap::renderPostFx(CameraMode cam_mode)
  556. {
  557. // Sadly ISceneManager has no "post effects" render pass, in that case we
  558. // could just register for that and handle it in renderMap().
  559. MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS));
  560. // - If the player is in a solid node, make everything black.
  561. // - If the player is in liquid, draw a semi-transparent overlay.
  562. // - Do not if player is in third person mode
  563. const ContentFeatures& features = m_nodedef->get(n);
  564. video::SColor post_effect_color = features.post_effect_color;
  565. if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
  566. m_client->checkLocalPrivilege("noclip")) &&
  567. cam_mode == CAMERA_MODE_FIRST)
  568. {
  569. post_effect_color = video::SColor(255, 0, 0, 0);
  570. }
  571. if (post_effect_color.getAlpha() != 0)
  572. {
  573. // Draw a full-screen rectangle
  574. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  575. v2u32 ss = driver->getScreenSize();
  576. core::rect<s32> rect(0,0, ss.X, ss.Y);
  577. driver->draw2DRectangle(post_effect_color, rect);
  578. }
  579. }
  580. void ClientMap::PrintInfo(std::ostream &out)
  581. {
  582. out<<"ClientMap: ";
  583. }