Luanti 5.11.0-dev
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Loading...
Searching...
No Matches
voxel.h
Go to the documentation of this file.
1// Luanti
2// SPDX-License-Identifier: LGPL-2.1-or-later
3// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5#pragma once
6
7#include "irrlichttypes.h"
8#include "irr_v3d.h"
9#include <iostream>
10#include <cassert>
11#include "exceptions.h"
12#include "mapnode.h"
13#include <set>
14#include <list>
16
17class NodeDefManager;
18
19// For VC++
20#undef min
21#undef max
22
23/*
24 A fast voxel manipulator class.
25
26 In normal operation, it fetches more map when it is requested.
27 It can also be used so that all allowed area is fetched at the
28 start, using ManualMapVoxelManipulator.
29
30 Not thread-safe.
31*/
32
33/*
34 Debug stuff
35*/
36extern u64 emerge_time;
37extern u64 emerge_load_time;
38
39/*
40 This class resembles aabbox3d<s16> a lot, but has inclusive
41 edges for saner handling of integer sizes
42*/
44{
45public:
46 // Starts as zero sized
47 constexpr VoxelArea() = default;
48
49 VoxelArea(const v3s16 &min_edge, const v3s16 &max_edge):
50 MinEdge(min_edge),
51 MaxEdge(max_edge)
52 {
54 }
55
56 VoxelArea(const v3s16 &p):
57 MinEdge(p),
58 MaxEdge(p)
59 {
61 }
62
63 /*
64 Modifying methods
65 */
66
67 void addArea(const VoxelArea &a)
68 {
69 if (hasEmptyExtent())
70 {
71 *this = a;
72 return;
73 }
74 if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
75 if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
76 if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
77 if(a.MaxEdge.X > MaxEdge.X) MaxEdge.X = a.MaxEdge.X;
78 if(a.MaxEdge.Y > MaxEdge.Y) MaxEdge.Y = a.MaxEdge.Y;
79 if(a.MaxEdge.Z > MaxEdge.Z) MaxEdge.Z = a.MaxEdge.Z;
81 }
82
83 void addPoint(const v3s16 &p)
84 {
85 if(hasEmptyExtent())
86 {
87 MinEdge = p;
88 MaxEdge = p;
90 return;
91 }
92 if(p.X < MinEdge.X) MinEdge.X = p.X;
93 if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
94 if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
95 if(p.X > MaxEdge.X) MaxEdge.X = p.X;
96 if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
97 if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
99 }
100
101 // Pad with d nodes
102 void pad(const v3s16 &d)
103 {
104 MinEdge -= d;
105 MaxEdge += d;
106 cacheExtent();
107 }
108
109 /*
110 const methods
111 */
112
113 const v3s32 &getExtent() const
114 {
115 return m_cache_extent;
116 }
117
118 bool hasEmptyExtent() const
119 {
120 return !m_cache_extent.X || !m_cache_extent.Y || !m_cache_extent.Z;
121 }
122
123 u32 getVolume() const
124 {
125 // FIXME: possible integer overflow here
126 return (u32)m_cache_extent.X * (u32)m_cache_extent.Y * (u32)m_cache_extent.Z;
127 }
128
129 bool contains(const VoxelArea &a) const
130 {
131 // No area contains an empty area
132 // NOTE: Algorithms depend on this, so do not change.
133 if(a.hasEmptyExtent())
134 return false;
135
136 return(
137 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
138 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
139 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
140 );
141 }
142 bool contains(v3s16 p) const
143 {
144 return(
145 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
146 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
147 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
148 );
149 }
150 bool contains(s32 i) const
151 {
152 return i >= 0 && static_cast<u32>(i) < getVolume();
153 }
154
155 bool operator==(const VoxelArea &other) const
156 {
157 return (MinEdge == other.MinEdge
158 && MaxEdge == other.MaxEdge);
159 }
160
161 VoxelArea operator+(const v3s16 &off) const
162 {
163 return {MinEdge+off, MaxEdge+off};
164 }
165
166 VoxelArea operator-(const v3s16 &off) const
167 {
168 return {MinEdge-off, MaxEdge-off};
169 }
170
171 /*
172 Returns the intersection of this area and `a`.
173 */
175 {
176 // This is an example of an operation that would be simpler with
177 // non-inclusive edges, but oh well.
178 VoxelArea ret;
179
180 if (a.MaxEdge.X < MinEdge.X || a.MinEdge.X > MaxEdge.X)
181 return VoxelArea();
182 if (a.MaxEdge.Y < MinEdge.Y || a.MinEdge.Y > MaxEdge.Y)
183 return VoxelArea();
184 if (a.MaxEdge.Z < MinEdge.Z || a.MinEdge.Z > MaxEdge.Z)
185 return VoxelArea();
186 ret.MinEdge.X = std::max(a.MinEdge.X, MinEdge.X);
187 ret.MaxEdge.X = std::min(a.MaxEdge.X, MaxEdge.X);
188 ret.MinEdge.Y = std::max(a.MinEdge.Y, MinEdge.Y);
189 ret.MaxEdge.Y = std::min(a.MaxEdge.Y, MaxEdge.Y);
190 ret.MinEdge.Z = std::max(a.MinEdge.Z, MinEdge.Z);
191 ret.MaxEdge.Z = std::min(a.MaxEdge.Z, MaxEdge.Z);
192 ret.cacheExtent();
193
194 return ret;
195 }
196
204 template <typename C>
205 void diff(const VoxelArea &a, C &result) const
206 {
207 // If a is an empty area, return the current area as a whole
208 if(a.hasEmptyExtent())
209 {
210 VoxelArea b = *this;
211 if (!b.hasEmptyExtent())
212 result.push_back(b);
213 return;
214 }
215
216 assert(contains(a)); // pre-condition
217
218 const auto &take = [&result] (v3s16 min, v3s16 max) {
219 VoxelArea b(min, max);
220 if (!b.hasEmptyExtent())
221 result.push_back(b);
222 };
223
224 // Take back area, XY inclusive
225 {
226 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
227 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
228 take(min, max);
229 }
230
231 // Take front area, XY inclusive
232 {
233 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
234 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
235 take(min, max);
236 }
237
238 // Take top area, X inclusive
239 {
240 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
241 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
242 take(min, max);
243 }
244
245 // Take bottom area, X inclusive
246 {
247 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
248 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
249 take(min, max);
250 }
251
252 // Take left area, non-inclusive
253 {
254 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
255 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
256 take(min, max);
257 }
258
259 // Take right area, non-inclusive
260 {
261 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
262 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
263 take(min, max);
264 }
265 }
266
267 /*
268 Translates position from virtual coordinates to array index
269 */
270 s32 index(s16 x, s16 y, s16 z) const
271 {
272 s32 i = (s32)(z - MinEdge.Z) * m_cache_extent.Y * m_cache_extent.X
273 + (y - MinEdge.Y) * m_cache_extent.X
274 + (x - MinEdge.X);
275 return i;
276 }
277 s32 index(v3s16 p) const
278 {
279 return index(p.X, p.Y, p.Z);
280 }
281
285 static void add_x(const v3s32 &extent, u32 &i, s16 a)
286 {
287 (void)extent;
288 i += a;
289 }
290
294 static void add_y(const v3s32 &extent, u32 &i, s16 a)
295 {
296 i += a * extent.X;
297 }
298
302 static void add_z(const v3s32 &extent, u32 &i, s16 a)
303 {
304 i += a * extent.X * extent.Y;
305 }
306
310 static void add_p(const v3s32 &extent, u32 &i, v3s16 a)
311 {
312 i += a.Z * extent.X * extent.Y + a.Y * extent.X + a.X;
313 }
314
315 /*
316 Print method for debugging
317 */
318 void print(std::ostream &o) const
319 {
320 o << MinEdge << MaxEdge << "="
321 << m_cache_extent.X << "x" << m_cache_extent.Y << "x" << m_cache_extent.Z
322 << "=" << getVolume();
323 }
324
331
332private:
334 {
336 MaxEdge.X - MinEdge.X + 1,
337 MaxEdge.Y - MinEdge.Y + 1,
338 MaxEdge.Z - MinEdge.Z + 1
339 };
340 // If positions were sorted correctly this must always hold.
341 // Note that this still permits empty areas (where MinEdge = MaxEdge + 1).
342 assert(m_cache_extent.X >= 0 && m_cache_extent.X <= MAX_EXTENT);
343 assert(m_cache_extent.Y >= 0 && m_cache_extent.Y <= MAX_EXTENT);
344 assert(m_cache_extent.Z >= 0 && m_cache_extent.Z <= MAX_EXTENT);
345 }
346
347 static constexpr s32 MAX_EXTENT = S16_MAX - S16_MIN + 1;
349};
350
351enum : u8 {
352 VOXELFLAG_NO_DATA = 1 << 0, // no data about that node
353 VOXELFLAG_CHECKED1 = 1 << 1, // Algorithm-dependent
354 VOXELFLAG_CHECKED2 = 1 << 2, // Algorithm-dependent
355 VOXELFLAG_CHECKED3 = 1 << 3, // Algorithm-dependent
356 VOXELFLAG_CHECKED4 = 1 << 4, // Algorithm-dependent
357};
358
366
368{
369public:
370 VoxelManipulator() = default;
371 virtual ~VoxelManipulator();
372
373 /*
374 These are a bit slow and shouldn't be used internally.
375 Use m_data[m_area.index(p)] instead.
376 */
378 {
379 VoxelArea voxel_area(p);
380 addArea(voxel_area);
381
382 const s32 index = m_area.index(p);
383
384 if (m_flags[index] & VOXELFLAG_NO_DATA) {
386 ("VoxelManipulator: getNode: inexistent");
387 }
388
389 return m_data[index];
390 }
392 {
393 VoxelArea voxel_area(p);
394 addArea(voxel_area);
395
396 const s32 index = m_area.index(p);
397
398 if (m_flags[index] & VOXELFLAG_NO_DATA) {
399 return {CONTENT_IGNORE};
400 }
401
402 return m_data[index];
403 }
405 {
406 if (!m_area.contains(p))
407 return {CONTENT_IGNORE};
408 const s32 index = m_area.index(p);
409 if (m_flags[index] & VOXELFLAG_NO_DATA)
410 return {CONTENT_IGNORE};
411 return m_data[index];
412 }
413 // Stuff explodes if non-emerged area is touched with this.
414 // Emerge first, and check VOXELFLAG_NO_DATA if appropriate.
416 {
417 return m_data[m_area.index(p)];
418 }
419
421 {
422 s32 index = m_area.index(p);
423
424 if (m_flags[index] & VOXELFLAG_NO_DATA)
425 return ContentIgnoreNode;
426
427 return m_data[index];
428 }
429
431 {
432 return m_flags[m_area.index(p)];
433 }
434
435 bool exists(const v3s16 &p)
436 {
437 return m_area.contains(p) &&
439 }
440
441 void setNode(const v3s16 &p, const MapNode &n)
442 {
443 VoxelArea voxel_area(p);
444 addArea(voxel_area);
445
446 const s32 index = m_area.index(p);
447
448 m_data[index] = n;
449 m_flags[index] &= ~VOXELFLAG_NO_DATA;
450 }
451
452 /*
453 Set stuff if available without an emerge.
454 Return false if failed.
455 This is convenient but slower than playing around directly
456 with the m_data table with indices.
457 */
459 {
460 if(!m_area.contains(p))
461 return false;
462 const s32 index = m_area.index(p);
463 m_data[index] = n;
464 m_flags[index] &= ~VOXELFLAG_NO_DATA;
465 return true;
466 }
467
468 /*
469 Control
470 */
471
472 virtual void clear();
473
474 void print(std::ostream &o, const NodeDefManager *nodemgr,
476
477 void addArea(const VoxelArea &area);
478
479 void setFlags(const VoxelArea &area, u8 flag);
480 void clearFlags(const VoxelArea &area, u8 flag);
481
482 /*
483 Copy data and set flags to 0
484 dst_area.getExtent() <= src_area.getExtent()
485 */
486 void copyFrom(MapNode *src, const VoxelArea& src_area,
487 v3s16 from_pos, v3s16 to_pos, const v3s16 &size);
488
489 // Copy data
490 void copyTo(MapNode *dst, const VoxelArea& dst_area,
491 v3s16 dst_pos, v3s16 from_pos, const v3s16 &size) const;
492
493 /*
494 Member variables
495 */
496
497 /*
498 The area that is stored in m_data.
499 MaxEdge is 1 higher than maximum allowed position.
500 */
502
503 /*
504 nullptr if data size is 0 (empty extent)
505 Data is stored as [z*h*w + y*h + x]
506 */
507 MapNode *m_data = nullptr;
508
509 /*
510 Flags of all nodes
511 */
512 u8 *m_flags = nullptr;
513
515};
Definition exceptions.h:108
This class is for getting the actual properties of nodes from their content ID.
Definition nodedef.h:530
Definition voxel.h:44
v3s16 MinEdge
Minimum edge of the area (inclusive)
Definition voxel.h:327
void addArea(const VoxelArea &a)
Definition voxel.h:67
bool contains(s32 i) const
Definition voxel.h:150
VoxelArea intersect(const VoxelArea &a) const
Definition voxel.h:174
static void add_p(const v3s32 &extent, u32 &i, v3s16 a)
Translate index in space.
Definition voxel.h:310
static constexpr s32 MAX_EXTENT
Definition voxel.h:347
s32 index(s16 x, s16 y, s16 z) const
Definition voxel.h:270
VoxelArea(const v3s16 &min_edge, const v3s16 &max_edge)
Definition voxel.h:49
const v3s32 & getExtent() const
Definition voxel.h:113
static void add_z(const v3s32 &extent, u32 &i, s16 a)
Translate index in the Z coordinate.
Definition voxel.h:302
u32 getVolume() const
Definition voxel.h:123
VoxelArea operator-(const v3s16 &off) const
Definition voxel.h:166
bool contains(const VoxelArea &a) const
Definition voxel.h:129
static void add_y(const v3s32 &extent, u32 &i, s16 a)
Translate index in the Y coordinate.
Definition voxel.h:294
void cacheExtent()
Definition voxel.h:333
void addPoint(const v3s16 &p)
Definition voxel.h:83
v3s16 MaxEdge
Maximum edge of the area (inclusive)
Definition voxel.h:330
static void add_x(const v3s32 &extent, u32 &i, s16 a)
Translate index in the X coordinate.
Definition voxel.h:285
VoxelArea operator+(const v3s16 &off) const
Definition voxel.h:161
bool operator==(const VoxelArea &other) const
Definition voxel.h:155
s32 index(v3s16 p) const
Definition voxel.h:277
bool hasEmptyExtent() const
Definition voxel.h:118
void print(std::ostream &o) const
Definition voxel.h:318
void diff(const VoxelArea &a, C &result) const
Returns 0-6 non-overlapping areas that can be added to a to make up this area.
Definition voxel.h:205
void pad(const v3s16 &d)
Definition voxel.h:102
bool contains(v3s16 p) const
Definition voxel.h:142
v3s32 m_cache_extent
Definition voxel.h:348
constexpr VoxelArea()=default
VoxelArea(const v3s16 &p)
Definition voxel.h:56
Definition voxel.h:368
MapNode * m_data
Definition voxel.h:507
MapNode getNodeNoEx(const v3s16 &p)
Definition voxel.h:391
void print(std::ostream &o, const NodeDefManager *nodemgr, VoxelPrintMode mode=VOXELPRINT_MATERIAL) const
Definition voxel.cpp:38
const MapNode & getNodeRefUnsafeCheckFlags(const v3s16 &p) const
Definition voxel.h:420
u8 * m_flags
Definition voxel.h:512
void setFlags(const VoxelArea &area, u8 flag)
Definition voxel.cpp:251
void copyFrom(MapNode *src, const VoxelArea &src_area, v3s16 from_pos, v3s16 to_pos, const v3s16 &size)
Definition voxel.cpp:181
void copyTo(MapNode *dst, const VoxelArea &dst_area, v3s16 dst_pos, v3s16 from_pos, const v3s16 &size) const
Definition voxel.cpp:229
void setNode(const v3s16 &p, const MapNode &n)
Definition voxel.h:441
VoxelManipulator()=default
MapNode getNodeNoExNoEmerge(const v3s16 &p) const
Definition voxel.h:404
static const MapNode ContentIgnoreNode
Definition voxel.h:514
bool setNodeNoEmerge(const v3s16 &p, MapNode n)
Definition voxel.h:458
void addArea(const VoxelArea &area)
Definition voxel.cpp:128
bool exists(const v3s16 &p)
Definition voxel.h:435
u8 & getFlagsRefUnsafe(const v3s16 &p)
Definition voxel.h:430
void clearFlags(const VoxelArea &area, u8 flag)
Definition voxel.cpp:268
VoxelArea m_area
Definition voxel.h:501
MapNode & getNodeRefUnsafe(const v3s16 &p)
Definition voxel.h:415
virtual void clear()
Definition voxel.cpp:25
virtual ~VoxelManipulator()
Definition voxel.cpp:20
MapNode getNode(const v3s16 &p)
Definition voxel.h:377
core::vector3d< s32 > v3s32
Definition irr_v3d.h:15
core::vector3d< s16 > v3s16
Definition irr_v3d.h:13
#define S16_MAX
Definition irrlichttypes.h:23
#define S16_MIN
Definition irrlichttypes.h:18
#define CONTENT_IGNORE
Definition mapnode.h:58
Definition mapnode.h:124
static std::string p(std::string path)
Definition test_filesys.cpp:55
constexpr v3f x
Definition test_irr_matrix4.cpp:15
constexpr v3f y
Definition test_irr_matrix4.cpp:16
constexpr v3f z
Definition test_irr_matrix4.cpp:17
u64 emerge_load_time
Definition voxel.cpp:18
@ VOXELFLAG_NO_DATA
Definition voxel.h:352
@ VOXELFLAG_CHECKED3
Definition voxel.h:355
@ VOXELFLAG_CHECKED4
Definition voxel.h:356
@ VOXELFLAG_CHECKED1
Definition voxel.h:353
@ VOXELFLAG_CHECKED2
Definition voxel.h:354
VoxelPrintMode
Definition voxel.h:360
@ VOXELPRINT_WATERPRESSURE
Definition voxel.h:363
@ VOXELPRINT_NOTHING
Definition voxel.h:361
@ VOXELPRINT_LIGHT_DAY
Definition voxel.h:364
@ VOXELPRINT_MATERIAL
Definition voxel.h:362
u64 emerge_time
Definition voxel.cpp:17