voxel.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. Minetest
  3. Copyright (C) 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 "voxel.h"
  17. #include "map.h"
  18. #include "gettime.h"
  19. #include "nodedef.h"
  20. #include "util/directiontables.h"
  21. #include "util/timetaker.h"
  22. #include "porting.h"
  23. #include <cstring> // memcpy, memset
  24. /*
  25. Debug stuff
  26. */
  27. u64 addarea_time = 0;
  28. u64 emerge_time = 0;
  29. u64 emerge_load_time = 0;
  30. u64 clearflag_time = 0;
  31. VoxelManipulator::~VoxelManipulator()
  32. {
  33. clear();
  34. }
  35. void VoxelManipulator::clear()
  36. {
  37. // Reset area to empty volume
  38. VoxelArea old;
  39. std::swap(m_area, old);
  40. delete[] m_data;
  41. m_data = nullptr;
  42. delete[] m_flags;
  43. m_flags = nullptr;
  44. porting::TrackFreedMemory((sizeof(*m_data) + sizeof(*m_flags)) * old.getVolume());
  45. }
  46. void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
  47. VoxelPrintMode mode)
  48. {
  49. const v3s16 &em = m_area.getExtent();
  50. v3s16 of = m_area.MinEdge;
  51. o<<"size: "<<em.X<<"x"<<em.Y<<"x"<<em.Z
  52. <<" offset: ("<<of.X<<","<<of.Y<<","<<of.Z<<")"<<std::endl;
  53. for(s32 y=m_area.MaxEdge.Y; y>=m_area.MinEdge.Y; y--)
  54. {
  55. if(em.X >= 3 && em.Y >= 3)
  56. {
  57. if (y==m_area.MinEdge.Y+2) o<<"^ ";
  58. else if(y==m_area.MinEdge.Y+1) o<<"| ";
  59. else if(y==m_area.MinEdge.Y+0) o<<"y x-> ";
  60. else o<<" ";
  61. }
  62. for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
  63. {
  64. for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
  65. {
  66. u8 f = m_flags[m_area.index(x,y,z)];
  67. char c;
  68. if(f & VOXELFLAG_NO_DATA)
  69. c = 'N';
  70. else
  71. {
  72. c = 'X';
  73. MapNode n = m_data[m_area.index(x,y,z)];
  74. content_t m = n.getContent();
  75. u8 pr = n.param2;
  76. if(mode == VOXELPRINT_MATERIAL)
  77. {
  78. if(m <= 9)
  79. c = m + '0';
  80. }
  81. else if(mode == VOXELPRINT_WATERPRESSURE)
  82. {
  83. if(ndef->get(m).isLiquid())
  84. {
  85. c = 'w';
  86. if(pr <= 9)
  87. c = pr + '0';
  88. }
  89. else if(m == CONTENT_AIR)
  90. {
  91. c = ' ';
  92. }
  93. else
  94. {
  95. c = '#';
  96. }
  97. }
  98. else if(mode == VOXELPRINT_LIGHT_DAY)
  99. {
  100. if(ndef->get(m).light_source != 0)
  101. c = 'S';
  102. else if(!ndef->get(m).light_propagates)
  103. c = 'X';
  104. else
  105. {
  106. u8 light = n.getLight(LIGHTBANK_DAY, ndef->getLightingFlags(n));
  107. if(light < 10)
  108. c = '0' + light;
  109. else
  110. c = 'a' + (light-10);
  111. }
  112. }
  113. }
  114. o<<c;
  115. }
  116. o<<' ';
  117. }
  118. o<<std::endl;
  119. }
  120. }
  121. void VoxelManipulator::addArea(const VoxelArea &area)
  122. {
  123. // Cancel if requested area has zero volume
  124. if (area.hasEmptyExtent())
  125. return;
  126. // Cancel if m_area already contains the requested area
  127. if(m_area.contains(area))
  128. return;
  129. TimeTaker timer("addArea", &addarea_time);
  130. // Calculate new area
  131. VoxelArea new_area;
  132. // New area is the requested area if m_area has zero volume
  133. if(m_area.hasEmptyExtent())
  134. {
  135. new_area = area;
  136. }
  137. // Else add requested area to m_area
  138. else
  139. {
  140. new_area = m_area;
  141. new_area.addArea(area);
  142. }
  143. s32 new_size = new_area.getVolume();
  144. /*dstream<<"adding area ";
  145. area.print(dstream);
  146. dstream<<", old area ";
  147. m_area.print(dstream);
  148. dstream<<", new area ";
  149. new_area.print(dstream);
  150. dstream<<", new_size="<<new_size;
  151. dstream<<std::endl;*/
  152. // Allocate new data and clear flags
  153. MapNode *new_data = new MapNode[new_size];
  154. assert(new_data);
  155. u8 *new_flags = new u8[new_size];
  156. assert(new_flags);
  157. memset(new_flags, VOXELFLAG_NO_DATA, new_size);
  158. // Copy old data
  159. s32 old_x_width = m_area.MaxEdge.X - m_area.MinEdge.X + 1;
  160. for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
  161. for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
  162. {
  163. unsigned int old_index = m_area.index(m_area.MinEdge.X,y,z);
  164. unsigned int new_index = new_area.index(m_area.MinEdge.X,y,z);
  165. memcpy(&new_data[new_index], &m_data[old_index],
  166. old_x_width * sizeof(MapNode));
  167. memcpy(&new_flags[new_index], &m_flags[old_index],
  168. old_x_width * sizeof(u8));
  169. }
  170. // Replace area, data and flags
  171. m_area = new_area;
  172. MapNode *old_data = m_data;
  173. u8 *old_flags = m_flags;
  174. /*dstream<<"old_data="<<(int)old_data<<", new_data="<<(int)new_data
  175. <<", old_flags="<<(int)m_flags<<", new_flags="<<(int)new_flags<<std::endl;*/
  176. m_data = new_data;
  177. m_flags = new_flags;
  178. delete[] old_data;
  179. delete[] old_flags;
  180. //dstream<<"addArea done"<<std::endl;
  181. }
  182. void VoxelManipulator::copyFrom(MapNode *src, const VoxelArea& src_area,
  183. v3s16 from_pos, v3s16 to_pos, const v3s16 &size)
  184. {
  185. /* The reason for this optimised code is that we're a member function
  186. * and the data type/layout of m_data is know to us: it's stored as
  187. * [z*h*w + y*h + x]. Therefore we can take the calls to m_area index
  188. * (which performs the preceding mapping/indexing of m_data) out of the
  189. * inner loop and calculate the next index as we're iterating to gain
  190. * performance.
  191. *
  192. * src_step and dest_step is the amount required to be added to our index
  193. * every time y increments. Because the destination area may be larger
  194. * than the source area we need one additional variable (otherwise we could
  195. * just continue adding dest_step as is done for the source data): dest_mod.
  196. * dest_mod is the difference in size between a "row" in the source data
  197. * and a "row" in the destination data (I am using the term row loosely
  198. * and for illustrative purposes). E.g.
  199. *
  200. * src <-------------------->|'''''' dest mod ''''''''
  201. * dest <--------------------------------------------->
  202. *
  203. * dest_mod (it's essentially a modulus) is added to the destination index
  204. * after every full iteration of the y span.
  205. *
  206. * This method falls under the category "linear array and incrementing
  207. * index".
  208. */
  209. s32 src_step = src_area.getExtent().X;
  210. s32 dest_step = m_area.getExtent().X;
  211. s32 dest_mod = m_area.index(to_pos.X, to_pos.Y, to_pos.Z + 1)
  212. - m_area.index(to_pos.X, to_pos.Y, to_pos.Z)
  213. - dest_step * size.Y;
  214. s32 i_src = src_area.index(from_pos.X, from_pos.Y, from_pos.Z);
  215. s32 i_local = m_area.index(to_pos.X, to_pos.Y, to_pos.Z);
  216. for (s16 z = 0; z < size.Z; z++) {
  217. for (s16 y = 0; y < size.Y; y++) {
  218. memcpy(&m_data[i_local], &src[i_src], size.X * sizeof(*m_data));
  219. memset(&m_flags[i_local], 0, size.X);
  220. i_src += src_step;
  221. i_local += dest_step;
  222. }
  223. i_local += dest_mod;
  224. }
  225. }
  226. void VoxelManipulator::copyTo(MapNode *dst, const VoxelArea& dst_area,
  227. v3s16 dst_pos, v3s16 from_pos, const v3s16 &size)
  228. {
  229. for(s16 z=0; z<size.Z; z++)
  230. for(s16 y=0; y<size.Y; y++)
  231. {
  232. s32 i_dst = dst_area.index(dst_pos.X, dst_pos.Y+y, dst_pos.Z+z);
  233. s32 i_local = m_area.index(from_pos.X, from_pos.Y+y, from_pos.Z+z);
  234. for (s16 x = 0; x < size.X; x++) {
  235. if (m_data[i_local].getContent() != CONTENT_IGNORE)
  236. dst[i_dst] = m_data[i_local];
  237. i_dst++;
  238. i_local++;
  239. }
  240. }
  241. }
  242. /*
  243. Algorithms
  244. -----------------------------------------------------
  245. */
  246. void VoxelManipulator::clearFlag(u8 flags)
  247. {
  248. // 0-1ms on moderate area
  249. TimeTaker timer("clearFlag", &clearflag_time);
  250. //v3s16 s = m_area.getExtent();
  251. /*dstream<<"clearFlag clearing area of size "
  252. <<""<<s.X<<"x"<<s.Y<<"x"<<s.Z<<""
  253. <<std::endl;*/
  254. //s32 count = 0;
  255. /*for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
  256. for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
  257. for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
  258. {
  259. u8 f = m_flags[m_area.index(x,y,z)];
  260. m_flags[m_area.index(x,y,z)] &= ~flags;
  261. if(m_flags[m_area.index(x,y,z)] != f)
  262. count++;
  263. }*/
  264. s32 volume = m_area.getVolume();
  265. for(s32 i=0; i<volume; i++)
  266. {
  267. m_flags[i] &= ~flags;
  268. }
  269. /*s32 volume = m_area.getVolume();
  270. for(s32 i=0; i<volume; i++)
  271. {
  272. u8 f = m_flags[i];
  273. m_flags[i] &= ~flags;
  274. if(m_flags[i] != f)
  275. count++;
  276. }
  277. dstream<<"clearFlag changed "<<count<<" flags out of "
  278. <<volume<<" nodes"<<std::endl;*/
  279. }
  280. const MapNode VoxelManipulator::ContentIgnoreNode = MapNode(CONTENT_IGNORE);
  281. //END