nlist: make selected list accessible globally
[waspsaliva.git] / src / voxel.h
blob16540e5951b817849901770c1cec6476046f7992
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #pragma once
22 #include "irrlichttypes.h"
23 #include "irr_v3d.h"
24 #include <iostream>
25 #include <cassert>
26 #include "exceptions.h"
27 #include "mapnode.h"
28 #include <set>
29 #include <list>
30 #include "util/basic_macros.h"
32 class NodeDefManager;
34 // For VC++
35 #undef min
36 #undef max
39 A fast voxel manipulator class.
41 In normal operation, it fetches more map when it is requested.
42 It can also be used so that all allowed area is fetched at the
43 start, using ManualMapVoxelManipulator.
45 Not thread-safe.
49 Debug stuff
51 extern u64 emerge_time;
52 extern u64 emerge_load_time;
55 This class resembles aabbox3d<s16> a lot, but has inclusive
56 edges for saner handling of integer sizes
58 class VoxelArea
60 public:
61 // Starts as zero sized
62 VoxelArea() = default;
64 VoxelArea(const v3s16 &min_edge, const v3s16 &max_edge):
65 MinEdge(min_edge),
66 MaxEdge(max_edge)
68 cacheExtent();
71 VoxelArea(const v3s16 &p):
72 MinEdge(p),
73 MaxEdge(p)
75 cacheExtent();
79 Modifying methods
82 void addArea(const VoxelArea &a)
84 if (hasEmptyExtent())
86 *this = a;
87 return;
89 if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
90 if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
91 if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
92 if(a.MaxEdge.X > MaxEdge.X) MaxEdge.X = a.MaxEdge.X;
93 if(a.MaxEdge.Y > MaxEdge.Y) MaxEdge.Y = a.MaxEdge.Y;
94 if(a.MaxEdge.Z > MaxEdge.Z) MaxEdge.Z = a.MaxEdge.Z;
95 cacheExtent();
98 void addPoint(const v3s16 &p)
100 if(hasEmptyExtent())
102 MinEdge = p;
103 MaxEdge = p;
104 cacheExtent();
105 return;
107 if(p.X < MinEdge.X) MinEdge.X = p.X;
108 if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
109 if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
110 if(p.X > MaxEdge.X) MaxEdge.X = p.X;
111 if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
112 if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
113 cacheExtent();
116 // Pad with d nodes
117 void pad(const v3s16 &d)
119 MinEdge -= d;
120 MaxEdge += d;
124 const methods
127 const v3s16 &getExtent() const
129 return m_cache_extent;
132 /* Because MaxEdge and MinEdge are included in the voxel area an empty extent
133 * is not represented by (0, 0, 0), but instead (-1, -1, -1)
135 bool hasEmptyExtent() const
137 return MaxEdge - MinEdge == v3s16(-1, -1, -1);
140 s32 getVolume() const
142 return (s32)m_cache_extent.X * (s32)m_cache_extent.Y * (s32)m_cache_extent.Z;
145 bool contains(const VoxelArea &a) const
147 // No area contains an empty area
148 // NOTE: Algorithms depend on this, so do not change.
149 if(a.hasEmptyExtent())
150 return false;
152 return(
153 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
154 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
155 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
158 bool contains(v3s16 p) const
160 return(
161 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
162 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
163 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
166 bool contains(s32 i) const
168 return (i >= 0 && i < getVolume());
170 bool operator==(const VoxelArea &other) const
172 return (MinEdge == other.MinEdge
173 && MaxEdge == other.MaxEdge);
176 VoxelArea operator+(const v3s16 &off) const
178 return {MinEdge+off, MaxEdge+off};
181 VoxelArea operator-(const v3s16 &off) const
183 return {MinEdge-off, MaxEdge-off};
187 Returns 0-6 non-overlapping areas that can be added to
188 a to make up this area.
190 a: area inside *this
192 void diff(const VoxelArea &a, std::list<VoxelArea> &result)
195 This can result in a maximum of 6 areas
198 // If a is an empty area, return the current area as a whole
199 if(a.getExtent() == v3s16(0,0,0))
201 VoxelArea b = *this;
202 if(b.getVolume() != 0)
203 result.push_back(b);
204 return;
207 assert(contains(a)); // pre-condition
209 // Take back area, XY inclusive
211 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
212 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
213 VoxelArea b(min, max);
214 if(b.getVolume() != 0)
215 result.push_back(b);
218 // Take front area, XY inclusive
220 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
221 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
222 VoxelArea b(min, max);
223 if(b.getVolume() != 0)
224 result.push_back(b);
227 // Take top area, X inclusive
229 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
230 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
231 VoxelArea b(min, max);
232 if(b.getVolume() != 0)
233 result.push_back(b);
236 // Take bottom area, X inclusive
238 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
239 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
240 VoxelArea b(min, max);
241 if(b.getVolume() != 0)
242 result.push_back(b);
245 // Take left area, non-inclusive
247 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
248 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
249 VoxelArea b(min, max);
250 if(b.getVolume() != 0)
251 result.push_back(b);
254 // Take right area, non-inclusive
256 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
257 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
258 VoxelArea b(min, max);
259 if(b.getVolume() != 0)
260 result.push_back(b);
266 Translates position from virtual coordinates to array index
268 s32 index(s16 x, s16 y, s16 z) const
270 s32 i = (s32)(z - MinEdge.Z) * m_cache_extent.Y * m_cache_extent.X
271 + (y - MinEdge.Y) * m_cache_extent.X
272 + (x - MinEdge.X);
273 return i;
275 s32 index(v3s16 p) const
277 return index(p.X, p.Y, p.Z);
281 * Translate index in the X coordinate
283 static void add_x(const v3s16 &extent, u32 &i, s16 a)
285 i += a;
289 * Translate index in the Y coordinate
291 static void add_y(const v3s16 &extent, u32 &i, s16 a)
293 i += a * extent.X;
297 * Translate index in the Z coordinate
299 static void add_z(const v3s16 &extent, u32 &i, s16 a)
301 i += a * extent.X * extent.Y;
305 * Translate index in space
307 static void add_p(const v3s16 &extent, u32 &i, v3s16 a)
309 i += a.Z * extent.X * extent.Y + a.Y * extent.X + a.X;
313 Print method for debugging
315 void print(std::ostream &o) const
317 o << PP(MinEdge) << PP(MaxEdge) << "="
318 << m_cache_extent.X << "x" << m_cache_extent.Y << "x" << m_cache_extent.Z
319 << "=" << getVolume();
322 // Edges are inclusive
323 v3s16 MinEdge = v3s16(1,1,1);
324 v3s16 MaxEdge;
325 private:
326 void cacheExtent()
328 m_cache_extent = MaxEdge - MinEdge + v3s16(1,1,1);
331 v3s16 m_cache_extent = v3s16(0,0,0);
334 // unused
335 #define VOXELFLAG_UNUSED (1 << 0)
336 // no data about that node
337 #define VOXELFLAG_NO_DATA (1 << 1)
338 // Algorithm-dependent
339 #define VOXELFLAG_CHECKED1 (1 << 2)
340 // Algorithm-dependent
341 #define VOXELFLAG_CHECKED2 (1 << 3)
342 // Algorithm-dependent
343 #define VOXELFLAG_CHECKED3 (1 << 4)
344 // Algorithm-dependent
345 #define VOXELFLAG_CHECKED4 (1 << 5)
347 enum VoxelPrintMode
349 VOXELPRINT_NOTHING,
350 VOXELPRINT_MATERIAL,
351 VOXELPRINT_WATERPRESSURE,
352 VOXELPRINT_LIGHT_DAY,
355 class VoxelManipulator
357 public:
358 VoxelManipulator() = default;
359 virtual ~VoxelManipulator();
362 These are a bit slow and shouldn't be used internally.
363 Use m_data[m_area.index(p)] instead.
365 MapNode getNode(const v3s16 &p)
367 VoxelArea voxel_area(p);
368 addArea(voxel_area);
370 if (m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA) {
371 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
372 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
373 <<", index="<<m_area.index(p)
374 <<", flags="<<(int)m_flags[m_area.index(p)]
375 <<" is inexistent"<<std::endl;*/
376 throw InvalidPositionException
377 ("VoxelManipulator: getNode: inexistent");
380 return m_data[m_area.index(p)];
382 MapNode getNodeNoEx(const v3s16 &p)
384 VoxelArea voxel_area(p);
385 addArea(voxel_area);
387 if (m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA) {
388 return {CONTENT_IGNORE};
391 return m_data[m_area.index(p)];
393 MapNode getNodeNoExNoEmerge(const v3s16 &p)
395 if (!m_area.contains(p))
396 return {CONTENT_IGNORE};
397 if (m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
398 return {CONTENT_IGNORE};
399 return m_data[m_area.index(p)];
401 // Stuff explodes if non-emerged area is touched with this.
402 // Emerge first, and check VOXELFLAG_NO_DATA if appropriate.
403 MapNode & getNodeRefUnsafe(const v3s16 &p)
405 return m_data[m_area.index(p)];
408 const MapNode & getNodeRefUnsafeCheckFlags(const v3s16 &p)
410 s32 index = m_area.index(p);
412 if (m_flags[index] & VOXELFLAG_NO_DATA)
413 return ContentIgnoreNode;
415 return m_data[index];
418 u8 & getFlagsRefUnsafe(const v3s16 &p)
420 return m_flags[m_area.index(p)];
423 bool exists(const v3s16 &p)
425 return m_area.contains(p) &&
426 !(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA);
429 void setNode(const v3s16 &p, const MapNode &n)
431 VoxelArea voxel_area(p);
432 addArea(voxel_area);
434 m_data[m_area.index(p)] = n;
435 m_flags[m_area.index(p)] &= ~VOXELFLAG_NO_DATA;
437 // TODO: Should be removed and replaced with setNode
438 void setNodeNoRef(const v3s16 &p, const MapNode &n)
440 setNode(p, n);
444 Set stuff if available without an emerge.
445 Return false if failed.
446 This is convenient but slower than playing around directly
447 with the m_data table with indices.
449 bool setNodeNoEmerge(const v3s16 &p, MapNode n)
451 if(!m_area.contains(p))
452 return false;
453 m_data[m_area.index(p)] = n;
454 return true;
458 Control
461 virtual void clear();
463 void print(std::ostream &o, const NodeDefManager *nodemgr,
464 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
466 void addArea(const VoxelArea &area);
469 Copy data and set flags to 0
470 dst_area.getExtent() <= src_area.getExtent()
472 void copyFrom(MapNode *src, const VoxelArea& src_area,
473 v3s16 from_pos, v3s16 to_pos, const v3s16 &size);
475 // Copy data
476 void copyTo(MapNode *dst, const VoxelArea& dst_area,
477 v3s16 dst_pos, v3s16 from_pos, const v3s16 &size);
480 Algorithms
483 void clearFlag(u8 flag);
486 Member variables
490 The area that is stored in m_data.
491 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
492 MaxEdge is 1 higher than maximum allowed position
494 VoxelArea m_area;
497 nullptr if data size is 0 (extent (0,0,0))
498 Data is stored as [z*h*w + y*h + x]
500 MapNode *m_data = nullptr;
503 Flags of all nodes
505 u8 *m_flags = nullptr;
507 static const MapNode ContentIgnoreNode;