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 v3s16 &getExtent() const
113 {
114 return m_cache_extent;
115 }
116
118 bool hasEmptyExtent() const
119 {
120 // FIXME: shouldn't this actually be a component-wise check?
121 return m_cache_extent == v3s16(0,0,0);
122 }
123
124 s32 getVolume() const
125 {
126 return (s32)m_cache_extent.X * (s32)m_cache_extent.Y * (s32)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 && i < getVolume());
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.getVolume() != 0)
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.getVolume() != 0)
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 v3s16 &extent, u32 &i, s16 a)
284 {
285 i += a;
286 }
287
291 static void add_y(const v3s16 &extent, u32 &i, s16 a)
292 {
293 i += a * extent.X;
294 }
295
299 static void add_z(const v3s16 &extent, u32 &i, s16 a)
300 {
301 i += a * extent.X * extent.Y;
302 }
303
307 static void add_p(const v3s16 &extent, u32 &i, v3s16 a)
308 {
309 i += a.Z * extent.X * extent.Y + a.Y * extent.X + a.X;
310 }
311
312 /*
313 Print method for debugging
314 */
315 void print(std::ostream &o) const
316 {
317 o << MinEdge << MaxEdge << "="
318 << m_cache_extent.X << "x" << m_cache_extent.Y << "x" << m_cache_extent.Z
319 << "=" << getVolume();
320 }
321
328
329private:
331 {
332 m_cache_extent = MaxEdge - MinEdge + v3s16(1,1,1);
333 // If positions were sorted correctly this must always hold.
334 // Note that this still permits empty areas (where MinEdge = MaxEdge + 1).
335 assert(m_cache_extent.X >= 0);
336 assert(m_cache_extent.Y >= 0);
337 assert(m_cache_extent.Z >= 0);
338 }
339
341};
342
343enum : u8 {
344 VOXELFLAG_NO_DATA = 1 << 0, // no data about that node
345 VOXELFLAG_CHECKED1 = 1 << 1, // Algorithm-dependent
346 VOXELFLAG_CHECKED2 = 1 << 2, // Algorithm-dependent
347 VOXELFLAG_CHECKED3 = 1 << 3, // Algorithm-dependent
348 VOXELFLAG_CHECKED4 = 1 << 4, // Algorithm-dependent
349};
350
358
360{
361public:
362 VoxelManipulator() = default;
363 virtual ~VoxelManipulator();
364
365 /*
366 These are a bit slow and shouldn't be used internally.
367 Use m_data[m_area.index(p)] instead.
368 */
370 {
371 VoxelArea voxel_area(p);
372 addArea(voxel_area);
373
374 const s32 index = m_area.index(p);
375
376 if (m_flags[index] & VOXELFLAG_NO_DATA) {
378 ("VoxelManipulator: getNode: inexistent");
379 }
380
381 return m_data[index];
382 }
384 {
385 VoxelArea voxel_area(p);
386 addArea(voxel_area);
387
388 const s32 index = m_area.index(p);
389
390 if (m_flags[index] & VOXELFLAG_NO_DATA) {
391 return {CONTENT_IGNORE};
392 }
393
394 return m_data[index];
395 }
397 {
398 if (!m_area.contains(p))
399 return {CONTENT_IGNORE};
400 const s32 index = m_area.index(p);
401 if (m_flags[index] & VOXELFLAG_NO_DATA)
402 return {CONTENT_IGNORE};
403 return m_data[index];
404 }
405 // Stuff explodes if non-emerged area is touched with this.
406 // Emerge first, and check VOXELFLAG_NO_DATA if appropriate.
408 {
409 return m_data[m_area.index(p)];
410 }
411
413 {
414 s32 index = m_area.index(p);
415
416 if (m_flags[index] & VOXELFLAG_NO_DATA)
417 return ContentIgnoreNode;
418
419 return m_data[index];
420 }
421
423 {
424 return m_flags[m_area.index(p)];
425 }
426
427 bool exists(const v3s16 &p)
428 {
429 return m_area.contains(p) &&
431 }
432
433 void setNode(const v3s16 &p, const MapNode &n)
434 {
435 VoxelArea voxel_area(p);
436 addArea(voxel_area);
437
438 const s32 index = m_area.index(p);
439
440 m_data[index] = n;
441 m_flags[index] &= ~VOXELFLAG_NO_DATA;
442 }
443
444 /*
445 Set stuff if available without an emerge.
446 Return false if failed.
447 This is convenient but slower than playing around directly
448 with the m_data table with indices.
449 */
451 {
452 if(!m_area.contains(p))
453 return false;
454 m_data[m_area.index(p)] = n;
455 return true;
456 }
457
458 /*
459 Control
460 */
461
462 virtual void clear();
463
464 void print(std::ostream &o, const NodeDefManager *nodemgr,
466
467 void addArea(const VoxelArea &area);
468
469 void setFlags(const VoxelArea &area, u8 flag);
470 void clearFlags(const VoxelArea &area, u8 flag);
471
472 /*
473 Copy data and set flags to 0
474 dst_area.getExtent() <= src_area.getExtent()
475 */
476 void copyFrom(MapNode *src, const VoxelArea& src_area,
477 v3s16 from_pos, v3s16 to_pos, const v3s16 &size);
478
479 // Copy data
480 void copyTo(MapNode *dst, const VoxelArea& dst_area,
481 v3s16 dst_pos, v3s16 from_pos, const v3s16 &size) const;
482
483 /*
484 Member variables
485 */
486
487 /*
488 The area that is stored in m_data.
489 MaxEdge is 1 higher than maximum allowed position.
490 */
492
493 /*
494 nullptr if data size is 0 (empty extent)
495 Data is stored as [z*h*w + y*h + x]
496 */
497 MapNode *m_data = nullptr;
498
499 /*
500 Flags of all nodes
501 */
502 u8 *m_flags = nullptr;
503
505};
Definition exceptions.h:108
This class is for getting the actual properties of nodes from their content ID.
Definition nodedef.h:540
Definition voxel.h:44
v3s16 MinEdge
Minimum edge of the area (inclusive)
Definition voxel.h:324
void addArea(const VoxelArea &a)
Definition voxel.h:67
bool contains(s32 i) const
Definition voxel.h:150
static void add_z(const v3s16 &extent, u32 &i, s16 a)
Translate index in the Z coordinate.
Definition voxel.h:299
VoxelArea intersect(const VoxelArea &a) const
Definition voxel.h:173
static void add_y(const v3s16 &extent, u32 &i, s16 a)
Translate index in the Y coordinate.
Definition voxel.h:291
static void add_p(const v3s16 &extent, u32 &i, v3s16 a)
Translate index in space.
Definition voxel.h:307
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
static void add_x(const v3s16 &extent, u32 &i, s16 a)
Translate index in the X coordinate.
Definition voxel.h:283
VoxelArea operator-(const v3s16 &off) const
Definition voxel.h:165
bool contains(const VoxelArea &a) const
Definition voxel.h:129
void cacheExtent()
Definition voxel.h:330
void addPoint(const v3s16 &p)
Definition voxel.h:83
v3s16 MaxEdge
Maximum edge of the area (inclusive)
Definition voxel.h:327
v3s16 m_cache_extent
Definition voxel.h:340
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:118
void print(std::ostream &o) const
Definition voxel.h:315
const v3s16 & getExtent() const
Definition voxel.h:112
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
s32 getVolume() const
Definition voxel.h:124
void pad(const v3s16 &d)
Definition voxel.h:102
bool contains(v3s16 p) const
Definition voxel.h:142
constexpr VoxelArea()=default
VoxelArea(const v3s16 &p)
Definition voxel.h:56
Definition voxel.h:360
MapNode * m_data
Definition voxel.h:497
MapNode getNodeNoEx(const v3s16 &p)
Definition voxel.h:383
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:412
u8 * m_flags
Definition voxel.h:502
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:433
VoxelManipulator()=default
MapNode getNodeNoExNoEmerge(const v3s16 &p) const
Definition voxel.h:396
static const MapNode ContentIgnoreNode
Definition voxel.h:504
bool setNodeNoEmerge(const v3s16 &p, MapNode n)
Definition voxel.h:450
void addArea(const VoxelArea &area)
Definition voxel.cpp:116
bool exists(const v3s16 &p)
Definition voxel.h:427
u8 & getFlagsRefUnsafe(const v3s16 &p)
Definition voxel.h:422
void clearFlags(const VoxelArea &area, u8 flag)
Definition voxel.cpp:264
VoxelArea m_area
Definition voxel.h:491
MapNode & getNodeRefUnsafe(const v3s16 &p)
Definition voxel.h:407
virtual void clear()
Definition voxel.cpp:25
virtual ~VoxelManipulator()
Definition voxel.cpp:20
MapNode getNode(const v3s16 &p)
Definition voxel.h:369
core::vector3d< s16 > v3s16
Definition irr_v3d.h:13
#define CONTENT_IGNORE
Definition mapnode.h:58
Definition mapnode.h:124
static std::string p(std::string path)
Definition test_filesys.cpp:53
u64 emerge_load_time
Definition voxel.cpp:18
@ VOXELFLAG_NO_DATA
Definition voxel.h:344
@ VOXELFLAG_CHECKED3
Definition voxel.h:347
@ VOXELFLAG_CHECKED4
Definition voxel.h:348
@ VOXELFLAG_CHECKED1
Definition voxel.h:345
@ VOXELFLAG_CHECKED2
Definition voxel.h:346
VoxelPrintMode
Definition voxel.h:352
@ VOXELPRINT_WATERPRESSURE
Definition voxel.h:355
@ VOXELPRINT_NOTHING
Definition voxel.h:353
@ VOXELPRINT_LIGHT_DAY
Definition voxel.h:356
@ VOXELPRINT_MATERIAL
Definition voxel.h:354
u64 emerge_time
Definition voxel.cpp:17