clientmap.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  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. // struct MeshBufListList
  30. void MeshBufListList::clear()
  31. {
  32. for (auto &list : lists)
  33. list.clear();
  34. }
  35. void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
  36. {
  37. // Append to the correct layer
  38. std::vector<MeshBufList> &list = lists[layer];
  39. const video::SMaterial &m = buf->getMaterial();
  40. for (MeshBufList &l : list) {
  41. // comparing a full material is quite expensive so we don't do it if
  42. // not even first texture is equal
  43. if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
  44. continue;
  45. if (l.m == m) {
  46. l.bufs.emplace_back(position, buf);
  47. return;
  48. }
  49. }
  50. MeshBufList l;
  51. l.m = m;
  52. l.bufs.emplace_back(position, buf);
  53. list.emplace_back(l);
  54. }
  55. // ClientMap
  56. ClientMap::ClientMap(
  57. Client *client,
  58. RenderingEngine *rendering_engine,
  59. MapDrawControl &control,
  60. s32 id
  61. ):
  62. Map(client),
  63. scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
  64. rendering_engine->get_scene_manager(), id),
  65. m_client(client),
  66. m_rendering_engine(rendering_engine),
  67. m_control(control),
  68. m_drawlist(MapBlockComparer(v3s16(0,0,0)))
  69. {
  70. /*
  71. * @Liso: Sadly C++ doesn't have introspection, so the only way we have to know
  72. * the class is whith a name ;) Name property cames from ISceneNode base class.
  73. */
  74. Name = "ClientMap";
  75. m_box = aabb3f(-BS*1000000,-BS*1000000,-BS*1000000,
  76. BS*1000000,BS*1000000,BS*1000000);
  77. /* TODO: Add a callback function so these can be updated when a setting
  78. * changes. At this point in time it doesn't matter (e.g. /set
  79. * is documented to change server settings only)
  80. *
  81. * TODO: Local caching of settings is not optimal and should at some stage
  82. * be updated to use a global settings object for getting thse values
  83. * (as opposed to the this local caching). This can be addressed in
  84. * a later release.
  85. */
  86. m_cache_trilinear_filter = g_settings->getBool("trilinear_filter");
  87. m_cache_bilinear_filter = g_settings->getBool("bilinear_filter");
  88. m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter");
  89. m_cache_transparency_sorting_distance = g_settings->getU16("transparency_sorting_distance");
  90. }
  91. void ClientMap::updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset)
  92. {
  93. v3s16 previous_node = floatToInt(m_camera_position, BS) + m_camera_offset;
  94. v3s16 previous_block = getContainerPos(previous_node, MAP_BLOCKSIZE);
  95. m_camera_position = pos;
  96. m_camera_direction = dir;
  97. m_camera_fov = fov;
  98. m_camera_offset = offset;
  99. v3s16 current_node = floatToInt(m_camera_position, BS) + m_camera_offset;
  100. v3s16 current_block = getContainerPos(current_node, MAP_BLOCKSIZE);
  101. // reorder the blocks when camera crosses block boundary
  102. if (previous_block != current_block)
  103. m_needs_update_drawlist = true;
  104. // reorder transparent meshes when camera crosses node boundary
  105. if (previous_node != current_node)
  106. m_needs_update_transparent_meshes = true;
  107. }
  108. MapSector * ClientMap::emergeSector(v2s16 p2d)
  109. {
  110. // Check that it doesn't exist already
  111. MapSector *sector = getSectorNoGenerate(p2d);
  112. // Create it if it does not exist yet
  113. if (!sector) {
  114. sector = new MapSector(this, p2d, m_gamedef);
  115. m_sectors[p2d] = sector;
  116. }
  117. return sector;
  118. }
  119. void ClientMap::OnRegisterSceneNode()
  120. {
  121. if(IsVisible)
  122. {
  123. SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
  124. SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
  125. }
  126. ISceneNode::OnRegisterSceneNode();
  127. if (!m_added_to_shadow_renderer) {
  128. m_added_to_shadow_renderer = true;
  129. if (auto shadows = m_rendering_engine->get_shadow_renderer())
  130. shadows->addNodeToShadowList(this);
  131. }
  132. }
  133. void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
  134. v3s16 *p_blocks_min, v3s16 *p_blocks_max, float range)
  135. {
  136. if (range <= 0.0f)
  137. range = m_control.wanted_range;
  138. v3s16 box_nodes_d = range * v3s16(1, 1, 1);
  139. // Define p_nodes_min/max as v3s32 because 'cam_pos_nodes -/+ box_nodes_d'
  140. // can exceed the range of v3s16 when a large view range is used near the
  141. // world edges.
  142. v3s32 p_nodes_min(
  143. cam_pos_nodes.X - box_nodes_d.X,
  144. cam_pos_nodes.Y - box_nodes_d.Y,
  145. cam_pos_nodes.Z - box_nodes_d.Z);
  146. v3s32 p_nodes_max(
  147. cam_pos_nodes.X + box_nodes_d.X,
  148. cam_pos_nodes.Y + box_nodes_d.Y,
  149. cam_pos_nodes.Z + box_nodes_d.Z);
  150. // Take a fair amount as we will be dropping more out later
  151. // Umm... these additions are a bit strange but they are needed.
  152. *p_blocks_min = v3s16(
  153. p_nodes_min.X / MAP_BLOCKSIZE - 3,
  154. p_nodes_min.Y / MAP_BLOCKSIZE - 3,
  155. p_nodes_min.Z / MAP_BLOCKSIZE - 3);
  156. *p_blocks_max = v3s16(
  157. p_nodes_max.X / MAP_BLOCKSIZE + 1,
  158. p_nodes_max.Y / MAP_BLOCKSIZE + 1,
  159. p_nodes_max.Z / MAP_BLOCKSIZE + 1);
  160. }
  161. void ClientMap::updateDrawList()
  162. {
  163. ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
  164. m_needs_update_drawlist = false;
  165. for (auto &i : m_drawlist) {
  166. MapBlock *block = i.second;
  167. block->refDrop();
  168. }
  169. m_drawlist.clear();
  170. const v3f camera_position = m_camera_position;
  171. const v3f camera_direction = m_camera_direction;
  172. // Use a higher fov to accomodate faster camera movements.
  173. // Blocks are cropped better when they are drawn.
  174. const f32 camera_fov = m_camera_fov * 1.1f;
  175. v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
  176. v3s16 p_blocks_min;
  177. v3s16 p_blocks_max;
  178. getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
  179. // Read the vision range, unless unlimited range is enabled.
  180. float range = m_control.range_all ? 1e7 : m_control.wanted_range;
  181. // Number of blocks currently loaded by the client
  182. u32 blocks_loaded = 0;
  183. // Number of blocks with mesh in rendering range
  184. u32 blocks_in_range_with_mesh = 0;
  185. // Number of blocks occlusion culled
  186. u32 blocks_occlusion_culled = 0;
  187. // No occlusion culling when free_move is on and camera is inside ground
  188. bool occlusion_culling_enabled = true;
  189. if (m_control.allow_noclip) {
  190. MapNode n = getNode(cam_pos_nodes);
  191. if (n.getContent() == CONTENT_IGNORE || m_nodedef->get(n).solidness == 2)
  192. occlusion_culling_enabled = false;
  193. }
  194. v3s16 camera_block = getContainerPos(cam_pos_nodes, MAP_BLOCKSIZE);
  195. m_drawlist = std::map<v3s16, MapBlock*, MapBlockComparer>(MapBlockComparer(camera_block));
  196. // Uncomment to debug occluded blocks in the wireframe mode
  197. // TODO: Include this as a flag for an extended debugging setting
  198. //if (occlusion_culling_enabled && m_control.show_wireframe)
  199. // occlusion_culling_enabled = porting::getTimeS() & 1;
  200. for (const auto &sector_it : m_sectors) {
  201. MapSector *sector = sector_it.second;
  202. v2s16 sp = sector->getPos();
  203. blocks_loaded += sector->size();
  204. if (!m_control.range_all) {
  205. if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X ||
  206. sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z)
  207. continue;
  208. }
  209. MapBlockVect sectorblocks;
  210. sector->getBlocks(sectorblocks);
  211. /*
  212. Loop through blocks in sector
  213. */
  214. u32 sector_blocks_drawn = 0;
  215. for (MapBlock *block : sectorblocks) {
  216. /*
  217. Compare block position to camera position, skip
  218. if not seen on display
  219. */
  220. if (!block->mesh) {
  221. // Ignore if mesh doesn't exist
  222. continue;
  223. }
  224. v3s16 block_coord = block->getPos();
  225. v3s16 block_position = block->getPosRelative() + MAP_BLOCKSIZE / 2;
  226. // First, perform a simple distance check, with a padding of one extra block.
  227. if (!m_control.range_all &&
  228. block_position.getDistanceFrom(cam_pos_nodes) > range + MAP_BLOCKSIZE)
  229. continue; // Out of range, skip.
  230. // Keep the block alive as long as it is in range.
  231. block->resetUsageTimer();
  232. blocks_in_range_with_mesh++;
  233. // Frustum culling
  234. float d = 0.0;
  235. if (!isBlockInSight(block_coord, camera_position,
  236. camera_direction, camera_fov, range * BS, &d))
  237. continue;
  238. // Occlusion culling
  239. if ((!m_control.range_all && d > m_control.wanted_range * BS) ||
  240. (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes))) {
  241. blocks_occlusion_culled++;
  242. continue;
  243. }
  244. // Add to set
  245. block->refGrab();
  246. m_drawlist[block_coord] = block;
  247. sector_blocks_drawn++;
  248. } // foreach sectorblocks
  249. if (sector_blocks_drawn != 0)
  250. m_last_drawn_sectors.insert(sp);
  251. }
  252. g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh);
  253. g_profiler->avg("MapBlocks occlusion culled [#]", blocks_occlusion_culled);
  254. g_profiler->avg("MapBlocks drawn [#]", m_drawlist.size());
  255. g_profiler->avg("MapBlocks loaded [#]", blocks_loaded);
  256. }
  257. void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
  258. {
  259. bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
  260. std::string prefix;
  261. if (pass == scene::ESNRP_SOLID)
  262. prefix = "renderMap(SOLID): ";
  263. else
  264. prefix = "renderMap(TRANSPARENT): ";
  265. /*
  266. This is called two times per frame, reset on the non-transparent one
  267. */
  268. if (pass == scene::ESNRP_SOLID)
  269. m_last_drawn_sectors.clear();
  270. /*
  271. Get animation parameters
  272. */
  273. const float animation_time = m_client->getAnimationTime();
  274. const int crack = m_client->getCrackLevel();
  275. const u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
  276. const v3f camera_position = m_camera_position;
  277. /*
  278. Get all blocks and draw all visible ones
  279. */
  280. u32 vertex_count = 0;
  281. u32 drawcall_count = 0;
  282. // For limiting number of mesh animations per frame
  283. u32 mesh_animate_count = 0;
  284. //u32 mesh_animate_count_far = 0;
  285. /*
  286. Update transparent meshes
  287. */
  288. if (is_transparent_pass)
  289. updateTransparentMeshBuffers();
  290. /*
  291. Draw the selected MapBlocks
  292. */
  293. MeshBufListList grouped_buffers;
  294. std::vector<DrawDescriptor> draw_order;
  295. video::SMaterial previous_material;
  296. for (auto &i : m_drawlist) {
  297. v3s16 block_pos = i.first;
  298. MapBlock *block = i.second;
  299. // If the mesh of the block happened to get deleted, ignore it
  300. if (!block->mesh)
  301. continue;
  302. v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS);
  303. float d = camera_position.getDistanceFrom(block_pos_r);
  304. d = MYMAX(0,d - BLOCK_MAX_RADIUS);
  305. // Mesh animation
  306. if (pass == scene::ESNRP_SOLID) {
  307. MapBlockMesh *mapBlockMesh = block->mesh;
  308. assert(mapBlockMesh);
  309. // Pretty random but this should work somewhat nicely
  310. bool faraway = d >= BS * 50;
  311. if (mapBlockMesh->isAnimationForced() || !faraway ||
  312. mesh_animate_count < (m_control.range_all ? 200 : 50)) {
  313. bool animated = mapBlockMesh->animate(faraway, animation_time,
  314. crack, daynight_ratio);
  315. if (animated)
  316. mesh_animate_count++;
  317. } else {
  318. mapBlockMesh->decreaseAnimationForceTimer();
  319. }
  320. }
  321. /*
  322. Get the meshbuffers of the block
  323. */
  324. if (is_transparent_pass) {
  325. // In transparent pass, the mesh will give us
  326. // the partial buffers in the correct order
  327. for (auto &buffer : block->mesh->getTransparentBuffers())
  328. draw_order.emplace_back(block_pos, &buffer);
  329. }
  330. else {
  331. // otherwise, group buffers across meshes
  332. // using MeshBufListList
  333. MapBlockMesh *mapBlockMesh = block->mesh;
  334. assert(mapBlockMesh);
  335. for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
  336. scene::IMesh *mesh = mapBlockMesh->getMesh(layer);
  337. assert(mesh);
  338. u32 c = mesh->getMeshBufferCount();
  339. for (u32 i = 0; i < c; i++) {
  340. scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
  341. video::SMaterial& material = buf->getMaterial();
  342. video::IMaterialRenderer* rnd =
  343. driver->getMaterialRenderer(material.MaterialType);
  344. bool transparent = (rnd && rnd->isTransparent());
  345. if (!transparent) {
  346. if (buf->getVertexCount() == 0)
  347. errorstream << "Block [" << analyze_block(block)
  348. << "] contains an empty meshbuf" << std::endl;
  349. grouped_buffers.add(buf, block_pos, layer);
  350. }
  351. }
  352. }
  353. }
  354. }
  355. // Capture draw order for all solid meshes
  356. for (auto &lists : grouped_buffers.lists) {
  357. for (MeshBufList &list : lists) {
  358. // iterate in reverse to draw closest blocks first
  359. for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) {
  360. draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin());
  361. }
  362. }
  363. }
  364. TimeTaker draw("Drawing mesh buffers");
  365. core::matrix4 m; // Model matrix
  366. v3f offset = intToFloat(m_camera_offset, BS);
  367. u32 material_swaps = 0;
  368. // Render all mesh buffers in order
  369. drawcall_count += draw_order.size();
  370. for (auto &descriptor : draw_order) {
  371. scene::IMeshBuffer *buf = descriptor.getBuffer();
  372. // Check and abort if the machine is swapping a lot
  373. if (draw.getTimerTime() > 2000) {
  374. infostream << "ClientMap::renderMap(): Rendering took >2s, " <<
  375. "returning." << std::endl;
  376. return;
  377. }
  378. if (!descriptor.m_reuse_material) {
  379. auto &material = buf->getMaterial();
  380. // Apply filter settings
  381. material.setFlag(video::EMF_TRILINEAR_FILTER,
  382. m_cache_trilinear_filter);
  383. material.setFlag(video::EMF_BILINEAR_FILTER,
  384. m_cache_bilinear_filter);
  385. material.setFlag(video::EMF_ANISOTROPIC_FILTER,
  386. m_cache_anistropic_filter);
  387. material.setFlag(video::EMF_WIREFRAME,
  388. m_control.show_wireframe);
  389. // pass the shadow map texture to the buffer texture
  390. ShadowRenderer *shadow = m_rendering_engine->get_shadow_renderer();
  391. if (shadow && shadow->is_active()) {
  392. auto &layer = material.TextureLayer[ShadowRenderer::TEXTURE_LAYER_SHADOW];
  393. layer.Texture = shadow->get_texture();
  394. layer.TextureWrapU = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
  395. layer.TextureWrapV = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
  396. // Do not enable filter on shadow texture to avoid visual artifacts
  397. // with colored shadows.
  398. // Filtering is done in shader code anyway
  399. layer.BilinearFilter = false;
  400. layer.AnisotropicFilter = false;
  401. layer.TrilinearFilter = false;
  402. }
  403. driver->setMaterial(material);
  404. ++material_swaps;
  405. material.TextureLayer[ShadowRenderer::TEXTURE_LAYER_SHADOW].Texture = nullptr;
  406. }
  407. v3f block_wpos = intToFloat(descriptor.m_pos * MAP_BLOCKSIZE, BS);
  408. m.setTranslation(block_wpos - offset);
  409. driver->setTransform(video::ETS_WORLD, m);
  410. descriptor.draw(driver);
  411. vertex_count += buf->getIndexCount();
  412. }
  413. g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
  414. // Log only on solid pass because values are the same
  415. if (pass == scene::ESNRP_SOLID) {
  416. g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
  417. }
  418. if (pass == scene::ESNRP_TRANSPARENT) {
  419. g_profiler->avg("renderMap(): transparent buffers [#]", draw_order.size());
  420. }
  421. g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
  422. g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
  423. g_profiler->avg(prefix + "material swaps [#]", material_swaps);
  424. }
  425. static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
  426. float step_multiplier, float start_distance, float end_distance,
  427. const NodeDefManager *ndef, u32 daylight_factor, float sunlight_min_d,
  428. int *result, bool *sunlight_seen)
  429. {
  430. int brightness_sum = 0;
  431. int brightness_count = 0;
  432. float distance = start_distance;
  433. dir.normalize();
  434. v3f pf = p0;
  435. pf += dir * distance;
  436. int noncount = 0;
  437. bool nonlight_seen = false;
  438. bool allow_allowing_non_sunlight_propagates = false;
  439. bool allow_non_sunlight_propagates = false;
  440. // Check content nearly at camera position
  441. {
  442. v3s16 p = floatToInt(p0 /*+ dir * 3*BS*/, BS);
  443. MapNode n = map->getNode(p);
  444. if(ndef->get(n).param_type == CPT_LIGHT &&
  445. !ndef->get(n).sunlight_propagates)
  446. allow_allowing_non_sunlight_propagates = true;
  447. }
  448. // If would start at CONTENT_IGNORE, start closer
  449. {
  450. v3s16 p = floatToInt(pf, BS);
  451. MapNode n = map->getNode(p);
  452. if(n.getContent() == CONTENT_IGNORE){
  453. float newd = 2*BS;
  454. pf = p0 + dir * 2*newd;
  455. distance = newd;
  456. sunlight_min_d = 0;
  457. }
  458. }
  459. for (int i=0; distance < end_distance; i++) {
  460. pf += dir * step;
  461. distance += step;
  462. step *= step_multiplier;
  463. v3s16 p = floatToInt(pf, BS);
  464. MapNode n = map->getNode(p);
  465. if (allow_allowing_non_sunlight_propagates && i == 0 &&
  466. ndef->get(n).param_type == CPT_LIGHT &&
  467. !ndef->get(n).sunlight_propagates) {
  468. allow_non_sunlight_propagates = true;
  469. }
  470. if (ndef->get(n).param_type != CPT_LIGHT ||
  471. (!ndef->get(n).sunlight_propagates &&
  472. !allow_non_sunlight_propagates)){
  473. nonlight_seen = true;
  474. noncount++;
  475. if(noncount >= 4)
  476. break;
  477. continue;
  478. }
  479. if (distance >= sunlight_min_d && !*sunlight_seen && !nonlight_seen)
  480. if (n.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
  481. *sunlight_seen = true;
  482. noncount = 0;
  483. brightness_sum += decode_light(n.getLightBlend(daylight_factor, ndef));
  484. brightness_count++;
  485. }
  486. *result = 0;
  487. if(brightness_count == 0)
  488. return false;
  489. *result = brightness_sum / brightness_count;
  490. /*std::cerr<<"Sampled "<<brightness_count<<" points; result="
  491. <<(*result)<<std::endl;*/
  492. return true;
  493. }
  494. int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
  495. int oldvalue, bool *sunlight_seen_result)
  496. {
  497. ScopeProfiler sp(g_profiler, "CM::getBackgroundBrightness", SPT_AVG);
  498. static v3f z_directions[50] = {
  499. v3f(-100, 0, 0)
  500. };
  501. static f32 z_offsets[50] = {
  502. -1000,
  503. };
  504. if (z_directions[0].X < -99) {
  505. for (u32 i = 0; i < ARRLEN(z_directions); i++) {
  506. // Assumes FOV of 72 and 16/9 aspect ratio
  507. z_directions[i] = v3f(
  508. 0.02 * myrand_range(-100, 100),
  509. 1.0,
  510. 0.01 * myrand_range(-100, 100)
  511. ).normalize();
  512. z_offsets[i] = 0.01 * myrand_range(0,100);
  513. }
  514. }
  515. int sunlight_seen_count = 0;
  516. float sunlight_min_d = max_d*0.8;
  517. if(sunlight_min_d > 35*BS)
  518. sunlight_min_d = 35*BS;
  519. std::vector<int> values;
  520. values.reserve(ARRLEN(z_directions));
  521. for (u32 i = 0; i < ARRLEN(z_directions); i++) {
  522. v3f z_dir = z_directions[i];
  523. core::CMatrix4<f32> a;
  524. a.buildRotateFromTo(v3f(0,1,0), z_dir);
  525. v3f dir = m_camera_direction;
  526. a.rotateVect(dir);
  527. int br = 0;
  528. float step = BS*1.5;
  529. if(max_d > 35*BS)
  530. step = max_d / 35 * 1.5;
  531. float off = step * z_offsets[i];
  532. bool sunlight_seen_now = false;
  533. bool ok = getVisibleBrightness(this, m_camera_position, dir,
  534. step, 1.0, max_d*0.6+off, max_d, m_nodedef, daylight_factor,
  535. sunlight_min_d,
  536. &br, &sunlight_seen_now);
  537. if(sunlight_seen_now)
  538. sunlight_seen_count++;
  539. if(!ok)
  540. continue;
  541. values.push_back(br);
  542. // Don't try too much if being in the sun is clear
  543. if(sunlight_seen_count >= 20)
  544. break;
  545. }
  546. int brightness_sum = 0;
  547. int brightness_count = 0;
  548. std::sort(values.begin(), values.end());
  549. u32 num_values_to_use = values.size();
  550. if(num_values_to_use >= 10)
  551. num_values_to_use -= num_values_to_use/2;
  552. else if(num_values_to_use >= 7)
  553. num_values_to_use -= num_values_to_use/3;
  554. u32 first_value_i = (values.size() - num_values_to_use) / 2;
  555. for (u32 i=first_value_i; i < first_value_i + num_values_to_use; i++) {
  556. brightness_sum += values[i];
  557. brightness_count++;
  558. }
  559. int ret = 0;
  560. if(brightness_count == 0){
  561. MapNode n = getNode(floatToInt(m_camera_position, BS));
  562. if(m_nodedef->get(n).param_type == CPT_LIGHT){
  563. ret = decode_light(n.getLightBlend(daylight_factor, m_nodedef));
  564. } else {
  565. ret = oldvalue;
  566. }
  567. } else {
  568. ret = brightness_sum / brightness_count;
  569. }
  570. *sunlight_seen_result = (sunlight_seen_count > 0);
  571. return ret;
  572. }
  573. void ClientMap::renderPostFx(CameraMode cam_mode)
  574. {
  575. // Sadly ISceneManager has no "post effects" render pass, in that case we
  576. // could just register for that and handle it in renderMap().
  577. MapNode n = getNode(floatToInt(m_camera_position, BS));
  578. const ContentFeatures& features = m_nodedef->get(n);
  579. video::SColor post_effect_color = features.post_effect_color;
  580. // If the camera is in a solid node, make everything black.
  581. // (first person mode only)
  582. if (features.solidness == 2 && cam_mode == CAMERA_MODE_FIRST &&
  583. !m_control.allow_noclip) {
  584. post_effect_color = video::SColor(255, 0, 0, 0);
  585. }
  586. if (post_effect_color.getAlpha() != 0) {
  587. // Draw a full-screen rectangle
  588. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  589. v2u32 ss = driver->getScreenSize();
  590. core::rect<s32> rect(0,0, ss.X, ss.Y);
  591. driver->draw2DRectangle(post_effect_color, rect);
  592. }
  593. }
  594. void ClientMap::PrintInfo(std::ostream &out)
  595. {
  596. out<<"ClientMap: ";
  597. }
  598. void ClientMap::renderMapShadows(video::IVideoDriver *driver,
  599. const video::SMaterial &material, s32 pass, int frame, int total_frames)
  600. {
  601. bool is_transparent_pass = pass != scene::ESNRP_SOLID;
  602. std::string prefix;
  603. if (is_transparent_pass)
  604. prefix = "renderMap(SHADOW TRANS): ";
  605. else
  606. prefix = "renderMap(SHADOW SOLID): ";
  607. u32 drawcall_count = 0;
  608. u32 vertex_count = 0;
  609. MeshBufListList grouped_buffers;
  610. std::vector<DrawDescriptor> draw_order;
  611. int count = 0;
  612. int low_bound = is_transparent_pass ? 0 : m_drawlist_shadow.size() / total_frames * frame;
  613. int high_bound = is_transparent_pass ? m_drawlist_shadow.size() : m_drawlist_shadow.size() / total_frames * (frame + 1);
  614. // transparent pass should be rendered in one go
  615. if (is_transparent_pass && frame != total_frames - 1) {
  616. return;
  617. }
  618. for (auto &i : m_drawlist_shadow) {
  619. // only process specific part of the list & break early
  620. ++count;
  621. if (count <= low_bound)
  622. continue;
  623. if (count > high_bound)
  624. break;
  625. v3s16 block_pos = i.first;
  626. MapBlock *block = i.second;
  627. // If the mesh of the block happened to get deleted, ignore it
  628. if (!block->mesh)
  629. continue;
  630. /*
  631. Get the meshbuffers of the block
  632. */
  633. if (is_transparent_pass) {
  634. // In transparent pass, the mesh will give us
  635. // the partial buffers in the correct order
  636. for (auto &buffer : block->mesh->getTransparentBuffers())
  637. draw_order.emplace_back(block_pos, &buffer);
  638. }
  639. else {
  640. // otherwise, group buffers across meshes
  641. // using MeshBufListList
  642. MapBlockMesh *mapBlockMesh = block->mesh;
  643. assert(mapBlockMesh);
  644. for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
  645. scene::IMesh *mesh = mapBlockMesh->getMesh(layer);
  646. assert(mesh);
  647. u32 c = mesh->getMeshBufferCount();
  648. for (u32 i = 0; i < c; i++) {
  649. scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
  650. video::SMaterial &mat = buf->getMaterial();
  651. auto rnd = driver->getMaterialRenderer(mat.MaterialType);
  652. bool transparent = rnd && rnd->isTransparent();
  653. if (!transparent)
  654. grouped_buffers.add(buf, block_pos, layer);
  655. }
  656. }
  657. }
  658. }
  659. u32 buffer_count = 0;
  660. for (auto &lists : grouped_buffers.lists)
  661. for (MeshBufList &list : lists)
  662. buffer_count += list.bufs.size();
  663. draw_order.reserve(draw_order.size() + buffer_count);
  664. // Capture draw order for all solid meshes
  665. for (auto &lists : grouped_buffers.lists) {
  666. for (MeshBufList &list : lists) {
  667. // iterate in reverse to draw closest blocks first
  668. for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it)
  669. draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin());
  670. }
  671. }
  672. TimeTaker draw("Drawing shadow mesh buffers");
  673. core::matrix4 m; // Model matrix
  674. v3f offset = intToFloat(m_camera_offset, BS);
  675. u32 material_swaps = 0;
  676. // Render all mesh buffers in order
  677. drawcall_count += draw_order.size();
  678. for (auto &descriptor : draw_order) {
  679. scene::IMeshBuffer *buf = descriptor.getBuffer();
  680. // Check and abort if the machine is swapping a lot
  681. if (draw.getTimerTime() > 1000) {
  682. infostream << "ClientMap::renderMapShadows(): Rendering "
  683. "took >1s, returning." << std::endl;
  684. break;
  685. }
  686. if (!descriptor.m_reuse_material) {
  687. // override some material properties
  688. video::SMaterial local_material = buf->getMaterial();
  689. local_material.MaterialType = material.MaterialType;
  690. local_material.BackfaceCulling = material.BackfaceCulling;
  691. local_material.FrontfaceCulling = material.FrontfaceCulling;
  692. local_material.BlendOperation = material.BlendOperation;
  693. local_material.Lighting = false;
  694. driver->setMaterial(local_material);
  695. ++material_swaps;
  696. }
  697. v3f block_wpos = intToFloat(descriptor.m_pos * MAP_BLOCKSIZE, BS);
  698. m.setTranslation(block_wpos - offset);
  699. driver->setTransform(video::ETS_WORLD, m);
  700. descriptor.draw(driver);
  701. vertex_count += buf->getIndexCount();
  702. }
  703. // restore the driver material state
  704. video::SMaterial clean;
  705. clean.BlendOperation = video::EBO_ADD;
  706. driver->setMaterial(clean); // reset material to defaults
  707. driver->draw3DLine(v3f(), v3f(), video::SColor(0));
  708. g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
  709. g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
  710. g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
  711. g_profiler->avg(prefix + "material swaps [#]", material_swaps);
  712. }
  713. /*
  714. Custom update draw list for the pov of shadow light.
  715. */
  716. void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir, float radius, float length)
  717. {
  718. ScopeProfiler sp(g_profiler, "CM::updateDrawListShadow()", SPT_AVG);
  719. v3s16 cam_pos_nodes = floatToInt(shadow_light_pos, BS);
  720. v3s16 p_blocks_min;
  721. v3s16 p_blocks_max;
  722. getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max, radius + length);
  723. std::vector<v2s16> blocks_in_range;
  724. for (auto &i : m_drawlist_shadow) {
  725. MapBlock *block = i.second;
  726. block->refDrop();
  727. }
  728. m_drawlist_shadow.clear();
  729. // Number of blocks currently loaded by the client
  730. u32 blocks_loaded = 0;
  731. // Number of blocks with mesh in rendering range
  732. u32 blocks_in_range_with_mesh = 0;
  733. // Number of blocks occlusion culled
  734. u32 blocks_occlusion_culled = 0;
  735. for (auto &sector_it : m_sectors) {
  736. MapSector *sector = sector_it.second;
  737. if (!sector)
  738. continue;
  739. blocks_loaded += sector->size();
  740. MapBlockVect sectorblocks;
  741. sector->getBlocks(sectorblocks);
  742. /*
  743. Loop through blocks in sector
  744. */
  745. for (MapBlock *block : sectorblocks) {
  746. if (!block->mesh) {
  747. // Ignore if mesh doesn't exist
  748. continue;
  749. }
  750. v3f block_pos = intToFloat(block->getPos() * MAP_BLOCKSIZE, BS);
  751. v3f projection = shadow_light_pos + shadow_light_dir * shadow_light_dir.dotProduct(block_pos - shadow_light_pos);
  752. if (projection.getDistanceFrom(block_pos) > radius)
  753. continue;
  754. blocks_in_range_with_mesh++;
  755. // This block is in range. Reset usage timer.
  756. block->resetUsageTimer();
  757. // Add to set
  758. if (m_drawlist_shadow.find(block->getPos()) == m_drawlist_shadow.end()) {
  759. block->refGrab();
  760. m_drawlist_shadow[block->getPos()] = block;
  761. }
  762. }
  763. }
  764. g_profiler->avg("SHADOW MapBlock meshes in range [#]", blocks_in_range_with_mesh);
  765. g_profiler->avg("SHADOW MapBlocks occlusion culled [#]", blocks_occlusion_culled);
  766. g_profiler->avg("SHADOW MapBlocks drawn [#]", m_drawlist_shadow.size());
  767. g_profiler->avg("SHADOW MapBlocks loaded [#]", blocks_loaded);
  768. }
  769. void ClientMap::updateTransparentMeshBuffers()
  770. {
  771. ScopeProfiler sp(g_profiler, "CM::updateTransparentMeshBuffers", SPT_AVG);
  772. u32 sorted_blocks = 0;
  773. u32 unsorted_blocks = 0;
  774. f32 sorting_distance_sq = pow(m_cache_transparency_sorting_distance * BS, 2.0f);
  775. // Update the order of transparent mesh buffers in each mesh
  776. for (auto it = m_drawlist.begin(); it != m_drawlist.end(); it++) {
  777. MapBlock* block = it->second;
  778. if (!block->mesh)
  779. continue;
  780. if (m_needs_update_transparent_meshes ||
  781. block->mesh->getTransparentBuffers().size() == 0) {
  782. v3s16 block_pos = block->getPos();
  783. v3f block_pos_f = intToFloat(block_pos * MAP_BLOCKSIZE + MAP_BLOCKSIZE / 2, BS);
  784. f32 distance = m_camera_position.getDistanceFromSQ(block_pos_f);
  785. if (distance <= sorting_distance_sq) {
  786. block->mesh->updateTransparentBuffers(m_camera_position, block_pos);
  787. ++sorted_blocks;
  788. }
  789. else {
  790. block->mesh->consolidateTransparentBuffers();
  791. ++unsorted_blocks;
  792. }
  793. }
  794. }
  795. g_profiler->avg("CM::Transparent Buffers - Sorted", sorted_blocks);
  796. g_profiler->avg("CM::Transparent Buffers - Unsorted", unsorted_blocks);
  797. m_needs_update_transparent_meshes = false;
  798. }
  799. scene::IMeshBuffer* ClientMap::DrawDescriptor::getBuffer()
  800. {
  801. return m_use_partial_buffer ? m_partial_buffer->getBuffer() : m_buffer;
  802. }
  803. void ClientMap::DrawDescriptor::draw(video::IVideoDriver* driver)
  804. {
  805. if (m_use_partial_buffer) {
  806. m_partial_buffer->beforeDraw();
  807. driver->drawMeshBuffer(m_partial_buffer->getBuffer());
  808. m_partial_buffer->afterDraw();
  809. } else {
  810. driver->drawMeshBuffer(m_buffer);
  811. }
  812. }