Luanti 5.11.0-dev
 
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 }
107
108 /*
109 const methods
110 */
111
112 const v3s32 &getExtent() const
113 {
114 return m_cache_extent;
115 }
116
117 bool hasEmptyExtent() const
118 {
119 return !m_cache_extent.X || !m_cache_extent.Y || !m_cache_extent.Z;
120 }
121
122 u32 getVolume() const
123 {
124 // FIXME: possible integer overflow here
125 return (u32)m_cache_extent.X * (u32)m_cache_extent.Y * (u32)m_cache_extent.Z;
126 }
127
128 bool contains(const VoxelArea &a) const
129 {
130 // No area contains an empty area
131 // NOTE: Algorithms depend on this, so do not change.
132 if(a.hasEmptyExtent())
133 return false;
134
135 return(
136 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
137 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
138 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
139 );
140 }
141 bool contains(v3s16 p) const
142 {
143 return(
144 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
145 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
146 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
147 );
148 }
149 bool contains(s32 i) const
150 {
151 return i >= 0 && static_cast<u32>(i) < getVolume();
152 }
153
154 bool operator==(const VoxelArea &other) const
155 {
156 return (MinEdge == other.MinEdge
157 && MaxEdge == other.MaxEdge);
158 }
159
160 VoxelArea operator+(const v3s16 &off) const
161 {
162 return {MinEdge+off, MaxEdge+off};
163 }
164
165 VoxelArea operator-(const v3s16 &off) const
166 {
167 return {MinEdge-off, MaxEdge-off};
168 }
169
170 /*
171 Returns the intersection of this area and `a`.
172 */
174 {
175 // This is an example of an operation that would be simpler with
176 // non-inclusive edges, but oh well.
177 VoxelArea ret;
178
179 if (a.MaxEdge.X < MinEdge.X || a.MinEdge.X > MaxEdge.X)
180 return VoxelArea();
181 if (a.MaxEdge.Y < MinEdge.Y || a.MinEdge.Y > MaxEdge.Y)
182 return VoxelArea();
183 if (a.MaxEdge.Z < MinEdge.Z || a.MinEdge.Z > MaxEdge.Z)
184 return VoxelArea();
185 ret.MinEdge.X = std::max(a.MinEdge.X, MinEdge.X);
186 ret.MaxEdge.X = std::min(a.MaxEdge.X, MaxEdge.X);
187 ret.MinEdge.Y = std::max(a.MinEdge.Y, MinEdge.Y);
188 ret.MaxEdge.Y = std::min(a.MaxEdge.Y, MaxEdge.Y);
189 ret.MinEdge.Z = std::max(a.MinEdge.Z, MinEdge.Z);
190 ret.MaxEdge.Z = std::min(a.MaxEdge.Z, MaxEdge.Z);
191
192 return ret;
193 }
194
202 template <typename C>
203 void diff(const VoxelArea &a, C &result) const
204 {
205 // If a is an empty area, return the current area as a whole
206 if(a.hasEmptyExtent())
207 {
208 VoxelArea b = *this;
209 if (!b.hasEmptyExtent())
210 result.push_back(b);
211 return;
212 }
213
214 assert(contains(a)); // pre-condition
215
216 const auto &take = [&result] (v3s16 min, v3s16 max) {
217 VoxelArea b(min, max);
218 if (!b.hasEmptyExtent())
219 result.push_back(b);
220 };
221
222 // Take back area, XY inclusive
223 {
224 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
225 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
226 take(min, max);
227 }
228
229 // Take front area, XY inclusive
230 {
231 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
232 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
233 take(min, max);
234 }
235
236 // Take top area, X inclusive
237 {
238 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
239 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
240 take(min, max);
241 }
242
243 // Take bottom area, X inclusive
244 {
245 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
246 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
247 take(min, max);
248 }
249
250 // Take left area, non-inclusive
251 {
252 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
253 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
254 take(min, max);
255 }
256
257 // Take right area, non-inclusive
258 {
259 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
260 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
261 take(min, max);
262 }
263 }
264
265 /*
266 Translates position from virtual coordinates to array index
267 */
268 s32 index(s16 x, s16 y, s16 z) const
269 {
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;
274 }
275 s32 index(v3s16 p) const
276 {
277 return index(p.X, p.Y, p.Z);
278 }
279
283 static void add_x(const v3s32 &extent, u32 &i, s16 a)
284 {
285 (void)extent;
286 i += a;
287 }
288
292 static void add_y(const v3s32 &extent, u32 &i, s16 a)
293 {
294 i += a * extent.X;
295 }
296
300 static void add_z(const v3s32 &extent, u32 &i, s16 a)
301 {
302 i += a * extent.X * extent.Y;
303 }
304
308 static void add_p(const v3s32 &extent, u32 &i, v3s16 a)
309 {
310 i += a.Z * extent.X * extent.Y + a.Y * extent.X + a.X;
311 }
312
313 /*
314 Print method for debugging
315 */
316 void print(std::ostream &o) const
317 {
318 o << MinEdge << MaxEdge << "="
319 << m_cache_extent.X << "x" << m_cache_extent.Y << "x" << m_cache_extent.Z
320 << "=" << getVolume();
321 }
322
329
330private:
332 {
334 MaxEdge.X - MinEdge.X + 1,
335 MaxEdge.Y - MinEdge.Y + 1,
336 MaxEdge.Z - MinEdge.Z + 1
337 };
338 // If positions were sorted correctly this must always hold.
339 // Note that this still permits empty areas (where MinEdge = MaxEdge + 1).
340 assert(m_cache_extent.X >= 0 && m_cache_extent.X <= MAX_EXTENT);
341 assert(m_cache_extent.Y >= 0 && m_cache_extent.Y <= MAX_EXTENT);
342 assert(m_cache_extent.Z >= 0 && m_cache_extent.Z <= MAX_EXTENT);
343 }
344
345 static constexpr s32 MAX_EXTENT = S16_MAX - S16_MIN + 1;
347};
348
349enum : u8 {
350 VOXELFLAG_NO_DATA = 1 << 0, // no data about that node
351 VOXELFLAG_CHECKED1 = 1 << 1, // Algorithm-dependent
352 VOXELFLAG_CHECKED2 = 1 << 2, // Algorithm-dependent
353 VOXELFLAG_CHECKED3 = 1 << 3, // Algorithm-dependent
354 VOXELFLAG_CHECKED4 = 1 << 4, // Algorithm-dependent
355};
356
364
366{
367public:
368 VoxelManipulator() = default;
369 virtual ~VoxelManipulator();
370
371 /*
372 These are a bit slow and shouldn't be used internally.
373 Use m_data[m_area.index(p)] instead.
374 */
376 {
377 VoxelArea voxel_area(p);
378 addArea(voxel_area);
379
380 const s32 index = m_area.index(p);
381
382 if (m_flags[index] & VOXELFLAG_NO_DATA) {
384 ("VoxelManipulator: getNode: inexistent");
385 }
386
387 return m_data[index];
388 }
390 {
391 VoxelArea voxel_area(p);
392 addArea(voxel_area);
393
394 const s32 index = m_area.index(p);
395
396 if (m_flags[index] & VOXELFLAG_NO_DATA) {
397 return {CONTENT_IGNORE};
398 }
399
400 return m_data[index];
401 }
403 {
404 if (!m_area.contains(p))
405 return {CONTENT_IGNORE};
406 const s32 index = m_area.index(p);
407 if (m_flags[index] & VOXELFLAG_NO_DATA)
408 return {CONTENT_IGNORE};
409 return m_data[index];
410 }
411 // Stuff explodes if non-emerged area is touched with this.
412 // Emerge first, and check VOXELFLAG_NO_DATA if appropriate.
414 {
415 return m_data[m_area.index(p)];
416 }
417
419 {
420 s32 index = m_area.index(p);
421
422 if (m_flags[index] & VOXELFLAG_NO_DATA)
423 return ContentIgnoreNode;
424
425 return m_data[index];
426 }
427
429 {
430 return m_flags[m_area.index(p)];
431 }
432
433 bool exists(const v3s16 &p)
434 {
435 return m_area.contains(p) &&
437 }
438
439 void setNode(const v3s16 &p, const MapNode &n)
440 {
441 VoxelArea voxel_area(p);
442 addArea(voxel_area);
443
444 const s32 index = m_area.index(p);
445
446 m_data[index] = n;
447 m_flags[index] &= ~VOXELFLAG_NO_DATA;
448 }
449
450 /*
451 Set stuff if available without an emerge.
452 Return false if failed.
453 This is convenient but slower than playing around directly
454 with the m_data table with indices.
455 */
457 {
458 if(!m_area.contains(p))
459 return false;
460 m_data[m_area.index(p)] = n;
461 return true;
462 }
463
464 /*
465 Control
466 */
467
468 virtual void clear();
469
470 void print(std::ostream &o, const NodeDefManager *nodemgr,
472
473 void addArea(const VoxelArea &area);
474
475 void setFlags(const VoxelArea &area, u8 flag);
476 void clearFlags(const VoxelArea &area, u8 flag);
477
478 /*
479 Copy data and set flags to 0
480 dst_area.getExtent() <= src_area.getExtent()
481 */
482 void copyFrom(MapNode *src, const VoxelArea& src_area,
483 v3s16 from_pos, v3s16 to_pos, const v3s16 &size);
484
485 // Copy data
486 void copyTo(MapNode *dst, const VoxelArea& dst_area,
487 v3s16 dst_pos, v3s16 from_pos, const v3s16 &size) const;
488
489 /*
490 Member variables
491 */
492
493 /*
494 The area that is stored in m_data.
495 MaxEdge is 1 higher than maximum allowed position.
496 */
498
499 /*
500 nullptr if data size is 0 (empty extent)
501 Data is stored as [z*h*w + y*h + x]
502 */
503 MapNode *m_data = nullptr;
504
505 /*
506 Flags of all nodes
507 */
508 u8 *m_flags = nullptr;
509
511};
Definition exceptions.h:108
This class is for getting the actual properties of nodes from their content ID.
Definition nodedef.h:545
Definition voxel.h:44
v3s16 MinEdge
Minimum edge of the area (inclusive)
Definition voxel.h:325
void addArea(const VoxelArea &a)
Definition voxel.h:67
bool contains(s32 i) const
Definition voxel.h:149
VoxelArea intersect(const VoxelArea &a) const
Definition voxel.h:173
static void add_p(const v3s32 &extent, u32 &i, v3s16 a)
Translate index in space.
Definition voxel.h:308
static constexpr s32 MAX_EXTENT
Definition voxel.h:345
s32 index(s16 x, s16 y, s16 z) const
Definition voxel.h:268
VoxelArea(const v3s16 &min_edge, const v3s16 &max_edge)
Definition voxel.h:49
const v3s32 & getExtent() const
Definition voxel.h:112
static void add_z(const v3s32 &extent, u32 &i, s16 a)
Translate index in the Z coordinate.
Definition voxel.h:300
u32 getVolume() const
Definition voxel.h:122
VoxelArea operator-(const v3s16 &off) const
Definition voxel.h:165
bool contains(const VoxelArea &a) const
Definition voxel.h:128
static void add_y(const v3s32 &extent, u32 &i, s16 a)
Translate index in the Y coordinate.
Definition voxel.h:292
void cacheExtent()
Definition voxel.h:331
void addPoint(const v3s16 &p)
Definition voxel.h:83
v3s16 MaxEdge
Maximum edge of the area (inclusive)
Definition voxel.h:328
static void add_x(const v3s32 &extent, u32 &i, s16 a)
Translate index in the X coordinate.
Definition voxel.h:283
VoxelArea operator+(const v3s16 &off) const
Definition voxel.h:160
bool operator==(const VoxelArea &other) const
Definition voxel.h:154
s32 index(v3s16 p) const
Definition voxel.h:275
bool hasEmptyExtent() const
Definition voxel.h:117
void print(std::ostream &o) const
Definition voxel.h:316
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:203
void pad(const v3s16 &d)
Definition voxel.h:102
bool contains(v3s16 p) const
Definition voxel.h:141
v3s32 m_cache_extent
Definition voxel.h:346
constexpr VoxelArea()=default
VoxelArea(const v3s16 &p)
Definition voxel.h:56
Definition voxel.h:366
MapNode * m_data
Definition voxel.h:503
MapNode getNodeNoEx(const v3s16 &p)
Definition voxel.h:389
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:418
u8 * m_flags
Definition voxel.h:508
void setFlags(const VoxelArea &area, u8 flag)
Definition voxel.cpp:247
void copyFrom(MapNode *src, const VoxelArea &src_area, v3s16 from_pos, v3s16 to_pos, const v3s16 &size)
Definition voxel.cpp:177
void copyTo(MapNode *dst, const VoxelArea &dst_area, v3s16 dst_pos, v3s16 from_pos, const v3s16 &size) const
Definition voxel.cpp:225
void setNode(const v3s16 &p, const MapNode &n)
Definition voxel.h:439
VoxelManipulator()=default
MapNode getNodeNoExNoEmerge(const v3s16 &p) const
Definition voxel.h:402
static const MapNode ContentIgnoreNode
Definition voxel.h:510
bool setNodeNoEmerge(const v3s16 &p, MapNode n)
Definition voxel.h:456
void addArea(const VoxelArea &area)
Definition voxel.cpp:116
bool exists(const v3s16 &p)
Definition voxel.h:433
u8 & getFlagsRefUnsafe(const v3s16 &p)
Definition voxel.h:428
void clearFlags(const VoxelArea &area, u8 flag)
Definition voxel.cpp:264
VoxelArea m_area
Definition voxel.h:497
MapNode & getNodeRefUnsafe(const v3s16 &p)
Definition voxel.h:413
virtual void clear()
Definition voxel.cpp:25
virtual ~VoxelManipulator()
Definition voxel.cpp:20
MapNode getNode(const v3s16 &p)
Definition voxel.h:375
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:350
@ VOXELFLAG_CHECKED3
Definition voxel.h:353
@ VOXELFLAG_CHECKED4
Definition voxel.h:354
@ VOXELFLAG_CHECKED1
Definition voxel.h:351
@ VOXELFLAG_CHECKED2
Definition voxel.h:352
VoxelPrintMode
Definition voxel.h:358
@ VOXELPRINT_WATERPRESSURE
Definition voxel.h:361
@ VOXELPRINT_NOTHING
Definition voxel.h:359
@ VOXELPRINT_LIGHT_DAY
Definition voxel.h:362
@ VOXELPRINT_MATERIAL
Definition voxel.h:360
u64 emerge_time
Definition voxel.cpp:17