minimap.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2015 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 "minimap.h"
  17. #include <cmath>
  18. #include "client.h"
  19. #include "clientmap.h"
  20. #include "settings.h"
  21. #include "shader.h"
  22. #include "mapblock.h"
  23. #include "client/renderingengine.h"
  24. ////
  25. //// MinimapUpdateThread
  26. ////
  27. MinimapUpdateThread::~MinimapUpdateThread()
  28. {
  29. for (auto &it : m_blocks_cache) {
  30. delete it.second;
  31. }
  32. for (auto &q : m_update_queue) {
  33. delete q.data;
  34. }
  35. }
  36. bool MinimapUpdateThread::pushBlockUpdate(v3s16 pos, MinimapMapblock *data)
  37. {
  38. MutexAutoLock lock(m_queue_mutex);
  39. // Find if block is already in queue.
  40. // If it is, update the data and quit.
  41. for (QueuedMinimapUpdate &q : m_update_queue) {
  42. if (q.pos == pos) {
  43. delete q.data;
  44. q.data = data;
  45. return false;
  46. }
  47. }
  48. // Add the block
  49. QueuedMinimapUpdate q;
  50. q.pos = pos;
  51. q.data = data;
  52. m_update_queue.push_back(q);
  53. return true;
  54. }
  55. bool MinimapUpdateThread::popBlockUpdate(QueuedMinimapUpdate *update)
  56. {
  57. MutexAutoLock lock(m_queue_mutex);
  58. if (m_update_queue.empty())
  59. return false;
  60. *update = m_update_queue.front();
  61. m_update_queue.pop_front();
  62. return true;
  63. }
  64. void MinimapUpdateThread::enqueueBlock(v3s16 pos, MinimapMapblock *data)
  65. {
  66. pushBlockUpdate(pos, data);
  67. deferUpdate();
  68. }
  69. void MinimapUpdateThread::doUpdate()
  70. {
  71. QueuedMinimapUpdate update;
  72. while (popBlockUpdate(&update)) {
  73. if (update.data) {
  74. // Swap two values in the map using single lookup
  75. std::pair<std::map<v3s16, MinimapMapblock*>::iterator, bool>
  76. result = m_blocks_cache.insert(std::make_pair(update.pos, update.data));
  77. if (!result.second) {
  78. delete result.first->second;
  79. result.first->second = update.data;
  80. }
  81. } else {
  82. std::map<v3s16, MinimapMapblock *>::iterator it;
  83. it = m_blocks_cache.find(update.pos);
  84. if (it != m_blocks_cache.end()) {
  85. delete it->second;
  86. m_blocks_cache.erase(it);
  87. }
  88. }
  89. }
  90. if (data->map_invalidated && data->mode != MINIMAP_MODE_OFF) {
  91. getMap(data->pos, data->map_size, data->scan_height);
  92. data->map_invalidated = false;
  93. }
  94. }
  95. void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height)
  96. {
  97. v3s16 pos_min(pos.X - size / 2, pos.Y - height / 2, pos.Z - size / 2);
  98. v3s16 pos_max(pos_min.X + size - 1, pos.Y + height / 2, pos_min.Z + size - 1);
  99. v3s16 blockpos_min = getNodeBlockPos(pos_min);
  100. v3s16 blockpos_max = getNodeBlockPos(pos_max);
  101. // clear the map
  102. for (int z = 0; z < size; z++)
  103. for (int x = 0; x < size; x++) {
  104. MinimapPixel &mmpixel = data->minimap_scan[x + z * size];
  105. mmpixel.air_count = 0;
  106. mmpixel.height = 0;
  107. mmpixel.n = MapNode(CONTENT_AIR);
  108. }
  109. // draw the map
  110. v3s16 blockpos;
  111. for (blockpos.Z = blockpos_min.Z; blockpos.Z <= blockpos_max.Z; ++blockpos.Z)
  112. for (blockpos.Y = blockpos_min.Y; blockpos.Y <= blockpos_max.Y; ++blockpos.Y)
  113. for (blockpos.X = blockpos_min.X; blockpos.X <= blockpos_max.X; ++blockpos.X) {
  114. std::map<v3s16, MinimapMapblock *>::const_iterator pblock =
  115. m_blocks_cache.find(blockpos);
  116. if (pblock == m_blocks_cache.end())
  117. continue;
  118. const MinimapMapblock &block = *pblock->second;
  119. v3s16 block_node_min(blockpos * MAP_BLOCKSIZE);
  120. v3s16 block_node_max(block_node_min + MAP_BLOCKSIZE - 1);
  121. // clip
  122. v3s16 range_min = componentwise_max(block_node_min, pos_min);
  123. v3s16 range_max = componentwise_min(block_node_max, pos_max);
  124. v3s16 pos;
  125. pos.Y = range_min.Y;
  126. for (pos.Z = range_min.Z; pos.Z <= range_max.Z; ++pos.Z)
  127. for (pos.X = range_min.X; pos.X <= range_max.X; ++pos.X) {
  128. v3s16 inblock_pos = pos - block_node_min;
  129. const MinimapPixel &in_pixel =
  130. block.data[inblock_pos.Z * MAP_BLOCKSIZE + inblock_pos.X];
  131. v3s16 inmap_pos = pos - pos_min;
  132. MinimapPixel &out_pixel =
  133. data->minimap_scan[inmap_pos.X + inmap_pos.Z * size];
  134. out_pixel.air_count += in_pixel.air_count;
  135. if (in_pixel.n.param0 != CONTENT_AIR) {
  136. out_pixel.n = in_pixel.n;
  137. out_pixel.height = inmap_pos.Y + in_pixel.height;
  138. }
  139. }
  140. }
  141. }
  142. ////
  143. //// Mapper
  144. ////
  145. Minimap::Minimap(Client *client)
  146. {
  147. this->client = client;
  148. this->driver = RenderingEngine::get_video_driver();
  149. this->m_tsrc = client->getTextureSource();
  150. this->m_shdrsrc = client->getShaderSource();
  151. this->m_ndef = client->getNodeDefManager();
  152. m_angle = 0.f;
  153. // Initialize static settings
  154. m_enable_shaders = g_settings->getBool("enable_shaders");
  155. m_surface_mode_scan_height =
  156. g_settings->getBool("minimap_double_scan_height") ? 256 : 128;
  157. // Initialize minimap data
  158. data = new MinimapData;
  159. data->mode = MINIMAP_MODE_OFF;
  160. data->is_radar = false;
  161. data->map_invalidated = true;
  162. data->texture = NULL;
  163. data->heightmap_texture = NULL;
  164. data->minimap_shape_round = g_settings->getBool("minimap_shape_round");
  165. // Get round minimap textures
  166. data->minimap_mask_round = driver->createImage(
  167. m_tsrc->getTexture("minimap_mask_round.png"),
  168. core::position2d<s32>(0, 0),
  169. core::dimension2d<u32>(MINIMAP_MAX_SX, MINIMAP_MAX_SY));
  170. data->minimap_overlay_round = m_tsrc->getTexture("minimap_overlay_round.png");
  171. // Get square minimap textures
  172. data->minimap_mask_square = driver->createImage(
  173. m_tsrc->getTexture("minimap_mask_square.png"),
  174. core::position2d<s32>(0, 0),
  175. core::dimension2d<u32>(MINIMAP_MAX_SX, MINIMAP_MAX_SY));
  176. data->minimap_overlay_square = m_tsrc->getTexture("minimap_overlay_square.png");
  177. // Create player marker texture
  178. data->player_marker = m_tsrc->getTexture("player_marker.png");
  179. // Create object marker texture
  180. data->object_marker_red = m_tsrc->getTexture("object_marker_red.png");
  181. // Create mesh buffer for minimap
  182. m_meshbuffer = getMinimapMeshBuffer();
  183. // Initialize and start thread
  184. m_minimap_update_thread = new MinimapUpdateThread();
  185. m_minimap_update_thread->data = data;
  186. m_minimap_update_thread->start();
  187. }
  188. Minimap::~Minimap()
  189. {
  190. m_minimap_update_thread->stop();
  191. m_minimap_update_thread->wait();
  192. m_meshbuffer->drop();
  193. data->minimap_mask_round->drop();
  194. data->minimap_mask_square->drop();
  195. driver->removeTexture(data->texture);
  196. driver->removeTexture(data->heightmap_texture);
  197. driver->removeTexture(data->minimap_overlay_round);
  198. driver->removeTexture(data->minimap_overlay_square);
  199. driver->removeTexture(data->object_marker_red);
  200. delete data;
  201. delete m_minimap_update_thread;
  202. }
  203. void Minimap::addBlock(v3s16 pos, MinimapMapblock *data)
  204. {
  205. m_minimap_update_thread->enqueueBlock(pos, data);
  206. }
  207. void Minimap::toggleMinimapShape()
  208. {
  209. MutexAutoLock lock(m_mutex);
  210. data->minimap_shape_round = !data->minimap_shape_round;
  211. g_settings->setBool("minimap_shape_round", data->minimap_shape_round);
  212. m_minimap_update_thread->deferUpdate();
  213. }
  214. void Minimap::setMinimapShape(MinimapShape shape)
  215. {
  216. MutexAutoLock lock(m_mutex);
  217. if (shape == MINIMAP_SHAPE_SQUARE)
  218. data->minimap_shape_round = false;
  219. else if (shape == MINIMAP_SHAPE_ROUND)
  220. data->minimap_shape_round = true;
  221. g_settings->setBool("minimap_shape_round", data->minimap_shape_round);
  222. m_minimap_update_thread->deferUpdate();
  223. }
  224. MinimapShape Minimap::getMinimapShape()
  225. {
  226. if (data->minimap_shape_round) {
  227. return MINIMAP_SHAPE_ROUND;
  228. }
  229. return MINIMAP_SHAPE_SQUARE;
  230. }
  231. void Minimap::setMinimapMode(MinimapMode mode)
  232. {
  233. static const MinimapModeDef modedefs[MINIMAP_MODE_COUNT] = {
  234. {false, 0, 0},
  235. {false, m_surface_mode_scan_height, 256},
  236. {false, m_surface_mode_scan_height, 128},
  237. {false, m_surface_mode_scan_height, 64},
  238. {true, 32, 128},
  239. {true, 32, 64},
  240. {true, 32, 32}
  241. };
  242. if (mode >= MINIMAP_MODE_COUNT)
  243. return;
  244. MutexAutoLock lock(m_mutex);
  245. data->is_radar = modedefs[mode].is_radar;
  246. data->scan_height = modedefs[mode].scan_height;
  247. data->map_size = modedefs[mode].map_size;
  248. data->mode = mode;
  249. m_minimap_update_thread->deferUpdate();
  250. }
  251. void Minimap::setPos(v3s16 pos)
  252. {
  253. bool do_update = false;
  254. {
  255. MutexAutoLock lock(m_mutex);
  256. if (pos != data->old_pos) {
  257. data->old_pos = data->pos;
  258. data->pos = pos;
  259. do_update = true;
  260. }
  261. }
  262. if (do_update)
  263. m_minimap_update_thread->deferUpdate();
  264. }
  265. void Minimap::setAngle(f32 angle)
  266. {
  267. m_angle = angle;
  268. }
  269. void Minimap::blitMinimapPixelsToImageRadar(video::IImage *map_image)
  270. {
  271. video::SColor c(240, 0, 0, 0);
  272. for (s16 x = 0; x < data->map_size; x++)
  273. for (s16 z = 0; z < data->map_size; z++) {
  274. MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size];
  275. if (mmpixel->air_count > 0)
  276. c.setGreen(core::clamp(core::round32(32 + mmpixel->air_count * 8), 0, 255));
  277. else
  278. c.setGreen(0);
  279. map_image->setPixel(x, data->map_size - z - 1, c);
  280. }
  281. }
  282. void Minimap::blitMinimapPixelsToImageSurface(
  283. video::IImage *map_image, video::IImage *heightmap_image)
  284. {
  285. // This variable creation/destruction has a 1% cost on rendering minimap
  286. video::SColor tilecolor;
  287. for (s16 x = 0; x < data->map_size; x++)
  288. for (s16 z = 0; z < data->map_size; z++) {
  289. MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size];
  290. const ContentFeatures &f = m_ndef->get(mmpixel->n);
  291. const TileDef *tile = &f.tiledef[0];
  292. // Color of the 0th tile (mostly this is the topmost)
  293. if(tile->has_color)
  294. tilecolor = tile->color;
  295. else
  296. mmpixel->n.getColor(f, &tilecolor);
  297. tilecolor.setRed(tilecolor.getRed() * f.minimap_color.getRed() / 255);
  298. tilecolor.setGreen(tilecolor.getGreen() * f.minimap_color.getGreen() / 255);
  299. tilecolor.setBlue(tilecolor.getBlue() * f.minimap_color.getBlue() / 255);
  300. tilecolor.setAlpha(240);
  301. map_image->setPixel(x, data->map_size - z - 1, tilecolor);
  302. u32 h = mmpixel->height;
  303. heightmap_image->setPixel(x,data->map_size - z - 1,
  304. video::SColor(255, h, h, h));
  305. }
  306. }
  307. video::ITexture *Minimap::getMinimapTexture()
  308. {
  309. // update minimap textures when new scan is ready
  310. if (data->map_invalidated)
  311. return data->texture;
  312. // create minimap and heightmap images in memory
  313. core::dimension2d<u32> dim(data->map_size, data->map_size);
  314. video::IImage *map_image = driver->createImage(video::ECF_A8R8G8B8, dim);
  315. video::IImage *heightmap_image = driver->createImage(video::ECF_A8R8G8B8, dim);
  316. video::IImage *minimap_image = driver->createImage(video::ECF_A8R8G8B8,
  317. core::dimension2d<u32>(MINIMAP_MAX_SX, MINIMAP_MAX_SY));
  318. // Blit MinimapPixels to images
  319. if (data->is_radar)
  320. blitMinimapPixelsToImageRadar(map_image);
  321. else
  322. blitMinimapPixelsToImageSurface(map_image, heightmap_image);
  323. map_image->copyToScaling(minimap_image);
  324. map_image->drop();
  325. video::IImage *minimap_mask = data->minimap_shape_round ?
  326. data->minimap_mask_round : data->minimap_mask_square;
  327. if (minimap_mask) {
  328. for (s16 y = 0; y < MINIMAP_MAX_SY; y++)
  329. for (s16 x = 0; x < MINIMAP_MAX_SX; x++) {
  330. const video::SColor &mask_col = minimap_mask->getPixel(x, y);
  331. if (!mask_col.getAlpha())
  332. minimap_image->setPixel(x, y, video::SColor(0,0,0,0));
  333. }
  334. }
  335. if (data->texture)
  336. driver->removeTexture(data->texture);
  337. if (data->heightmap_texture)
  338. driver->removeTexture(data->heightmap_texture);
  339. data->texture = driver->addTexture("minimap__", minimap_image);
  340. data->heightmap_texture =
  341. driver->addTexture("minimap_heightmap__", heightmap_image);
  342. minimap_image->drop();
  343. heightmap_image->drop();
  344. data->map_invalidated = true;
  345. return data->texture;
  346. }
  347. v3f Minimap::getYawVec()
  348. {
  349. if (data->minimap_shape_round) {
  350. return v3f(
  351. std::cos(m_angle * core::DEGTORAD),
  352. std::sin(m_angle * core::DEGTORAD),
  353. 1.0);
  354. }
  355. return v3f(1.0, 0.0, 1.0);
  356. }
  357. scene::SMeshBuffer *Minimap::getMinimapMeshBuffer()
  358. {
  359. scene::SMeshBuffer *buf = new scene::SMeshBuffer();
  360. buf->Vertices.set_used(4);
  361. buf->Indices.set_used(6);
  362. static const video::SColor c(255, 255, 255, 255);
  363. buf->Vertices[0] = video::S3DVertex(-1, -1, 0, 0, 0, 1, c, 0, 1);
  364. buf->Vertices[1] = video::S3DVertex(-1, 1, 0, 0, 0, 1, c, 0, 0);
  365. buf->Vertices[2] = video::S3DVertex( 1, 1, 0, 0, 0, 1, c, 1, 0);
  366. buf->Vertices[3] = video::S3DVertex( 1, -1, 0, 0, 0, 1, c, 1, 1);
  367. buf->Indices[0] = 0;
  368. buf->Indices[1] = 1;
  369. buf->Indices[2] = 2;
  370. buf->Indices[3] = 2;
  371. buf->Indices[4] = 3;
  372. buf->Indices[5] = 0;
  373. return buf;
  374. }
  375. void Minimap::drawMinimap()
  376. {
  377. video::ITexture *minimap_texture = getMinimapTexture();
  378. if (!minimap_texture)
  379. return;
  380. updateActiveMarkers();
  381. v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
  382. const u32 size = 0.25 * screensize.Y;
  383. core::rect<s32> oldViewPort = driver->getViewPort();
  384. core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
  385. core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
  386. driver->setViewPort(core::rect<s32>(
  387. screensize.X - size - 10, 10,
  388. screensize.X - 10, size + 10));
  389. driver->setTransform(video::ETS_PROJECTION, core::matrix4());
  390. driver->setTransform(video::ETS_VIEW, core::matrix4());
  391. core::matrix4 matrix;
  392. matrix.makeIdentity();
  393. video::SMaterial &material = m_meshbuffer->getMaterial();
  394. material.setFlag(video::EMF_TRILINEAR_FILTER, true);
  395. material.Lighting = false;
  396. material.TextureLayer[0].Texture = minimap_texture;
  397. material.TextureLayer[1].Texture = data->heightmap_texture;
  398. if (m_enable_shaders && !data->is_radar) {
  399. u16 sid = m_shdrsrc->getShader("minimap_shader", 1, 1);
  400. material.MaterialType = m_shdrsrc->getShaderInfo(sid).material;
  401. } else {
  402. material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  403. }
  404. if (data->minimap_shape_round)
  405. matrix.setRotationDegrees(core::vector3df(0, 0, 360 - m_angle));
  406. // Draw minimap
  407. driver->setTransform(video::ETS_WORLD, matrix);
  408. driver->setMaterial(material);
  409. driver->drawMeshBuffer(m_meshbuffer);
  410. // Draw overlay
  411. video::ITexture *minimap_overlay = data->minimap_shape_round ?
  412. data->minimap_overlay_round : data->minimap_overlay_square;
  413. material.TextureLayer[0].Texture = minimap_overlay;
  414. material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  415. driver->setMaterial(material);
  416. driver->drawMeshBuffer(m_meshbuffer);
  417. // Draw player marker on minimap
  418. if (data->minimap_shape_round) {
  419. matrix.setRotationDegrees(core::vector3df(0, 0, 0));
  420. } else {
  421. matrix.setRotationDegrees(core::vector3df(0, 0, m_angle));
  422. }
  423. material.TextureLayer[0].Texture = data->player_marker;
  424. driver->setTransform(video::ETS_WORLD, matrix);
  425. driver->setMaterial(material);
  426. driver->drawMeshBuffer(m_meshbuffer);
  427. // Reset transformations
  428. driver->setTransform(video::ETS_VIEW, oldViewMat);
  429. driver->setTransform(video::ETS_PROJECTION, oldProjMat);
  430. driver->setViewPort(oldViewPort);
  431. // Draw player markers
  432. v2s32 s_pos(screensize.X - size - 10, 10);
  433. core::dimension2di imgsize(data->object_marker_red->getOriginalSize());
  434. core::rect<s32> img_rect(0, 0, imgsize.Width, imgsize.Height);
  435. static const video::SColor col(255, 255, 255, 255);
  436. static const video::SColor c[4] = {col, col, col, col};
  437. f32 sin_angle = std::sin(m_angle * core::DEGTORAD);
  438. f32 cos_angle = std::cos(m_angle * core::DEGTORAD);
  439. s32 marker_size2 = 0.025 * (float)size;
  440. for (std::list<v2f>::const_iterator
  441. i = m_active_markers.begin();
  442. i != m_active_markers.end(); ++i) {
  443. v2f posf = *i;
  444. if (data->minimap_shape_round) {
  445. f32 t1 = posf.X * cos_angle - posf.Y * sin_angle;
  446. f32 t2 = posf.X * sin_angle + posf.Y * cos_angle;
  447. posf.X = t1;
  448. posf.Y = t2;
  449. }
  450. posf.X = (posf.X + 0.5) * (float)size;
  451. posf.Y = (posf.Y + 0.5) * (float)size;
  452. core::rect<s32> dest_rect(
  453. s_pos.X + posf.X - marker_size2,
  454. s_pos.Y + posf.Y - marker_size2,
  455. s_pos.X + posf.X + marker_size2,
  456. s_pos.Y + posf.Y + marker_size2);
  457. driver->draw2DImage(data->object_marker_red, dest_rect,
  458. img_rect, &dest_rect, &c[0], true);
  459. }
  460. }
  461. void Minimap::updateActiveMarkers()
  462. {
  463. video::IImage *minimap_mask = data->minimap_shape_round ?
  464. data->minimap_mask_round : data->minimap_mask_square;
  465. const std::list<Nametag *> &nametags = client->getCamera()->getNametags();
  466. m_active_markers.clear();
  467. for (Nametag *nametag : nametags) {
  468. v3s16 pos = floatToInt(nametag->parent_node->getPosition() +
  469. intToFloat(client->getCamera()->getOffset(), BS), BS);
  470. pos -= data->pos - v3s16(data->map_size / 2,
  471. data->scan_height / 2,
  472. data->map_size / 2);
  473. if (pos.X < 0 || pos.X > data->map_size ||
  474. pos.Y < 0 || pos.Y > data->scan_height ||
  475. pos.Z < 0 || pos.Z > data->map_size) {
  476. continue;
  477. }
  478. pos.X = ((float)pos.X / data->map_size) * MINIMAP_MAX_SX;
  479. pos.Z = ((float)pos.Z / data->map_size) * MINIMAP_MAX_SY;
  480. const video::SColor &mask_col = minimap_mask->getPixel(pos.X, pos.Z);
  481. if (!mask_col.getAlpha()) {
  482. continue;
  483. }
  484. m_active_markers.emplace_back(((float)pos.X / (float)MINIMAP_MAX_SX) - 0.5,
  485. (1.0 - (float)pos.Z / (float)MINIMAP_MAX_SY) - 0.5);
  486. }
  487. }
  488. ////
  489. //// MinimapMapblock
  490. ////
  491. void MinimapMapblock::getMinimapNodes(VoxelManipulator *vmanip, const v3s16 &pos)
  492. {
  493. for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
  494. for (s16 z = 0; z < MAP_BLOCKSIZE; z++) {
  495. s16 air_count = 0;
  496. bool surface_found = false;
  497. MinimapPixel *mmpixel = &data[z * MAP_BLOCKSIZE + x];
  498. for (s16 y = MAP_BLOCKSIZE -1; y >= 0; y--) {
  499. v3s16 p(x, y, z);
  500. MapNode n = vmanip->getNodeNoEx(pos + p);
  501. if (!surface_found && n.getContent() != CONTENT_AIR) {
  502. mmpixel->height = y;
  503. mmpixel->n = n;
  504. surface_found = true;
  505. } else if (n.getContent() == CONTENT_AIR) {
  506. air_count++;
  507. }
  508. }
  509. if (!surface_found)
  510. mmpixel->n = MapNode(CONTENT_AIR);
  511. mmpixel->air_count = air_count;
  512. }
  513. }