voxel.cpp 8.2 KB

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