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.
23 #include "irrlichttypes.h"
27 #include "exceptions.h"
33 class INodeDefManager;
40 A fast voxel manipulator class.
42 In normal operation, it fetches more map when it is requested.
43 It can also be used so that all allowed area is fetched at the
44 start, using ManualMapVoxelManipulator.
52 extern u32 emerge_time;
53 extern u32 emerge_load_time;
56 This class resembles aabbox3d<s16> a lot, but has inclusive
57 edges for saner handling of integer sizes
62 // Starts as zero sized
68 VoxelArea(v3s16 min_edge, v3s16 max_edge):
83 void addArea(const VoxelArea &a)
90 if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
91 if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
92 if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
93 if(a.MaxEdge.X > MaxEdge.X) MaxEdge.X = a.MaxEdge.X;
94 if(a.MaxEdge.Y > MaxEdge.Y) MaxEdge.Y = a.MaxEdge.Y;
95 if(a.MaxEdge.Z > MaxEdge.Z) MaxEdge.Z = a.MaxEdge.Z;
97 void addPoint(const v3s16 &p)
105 if(p.X < MinEdge.X) MinEdge.X = p.X;
106 if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
107 if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
108 if(p.X > MaxEdge.X) MaxEdge.X = p.X;
109 if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
110 if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
114 void pad(const v3s16 &d)
120 /*void operator+=(v3s16 off)
126 void operator-=(v3s16 off)
136 v3s16 getExtent() const
138 return MaxEdge - MinEdge + v3s16(1,1,1);
141 /* Because MaxEdge and MinEdge are included in the voxel area an empty extent
142 * is not represented by (0, 0, 0), but instead (-1, -1, -1)
144 bool hasEmptyExtent() const
146 return MaxEdge - MinEdge == v3s16(-1, -1, -1);
149 s32 getVolume() const
151 v3s16 e = getExtent();
152 return (s32)e.X * (s32)e.Y * (s32)e.Z;
154 bool contains(const VoxelArea &a) const
156 // No area contains an empty area
157 // NOTE: Algorithms depend on this, so do not change.
158 if(a.hasEmptyExtent())
162 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
163 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
164 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
167 bool contains(v3s16 p) const
170 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
171 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
172 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
175 bool contains(s32 i) const
177 return (i >= 0 && i < getVolume());
179 bool operator==(const VoxelArea &other) const
181 return (MinEdge == other.MinEdge
182 && MaxEdge == other.MaxEdge);
185 VoxelArea operator+(v3s16 off) const
187 return VoxelArea(MinEdge+off, MaxEdge+off);
190 VoxelArea operator-(v3s16 off) const
192 return VoxelArea(MinEdge-off, MaxEdge-off);
196 Returns 0-6 non-overlapping areas that can be added to
197 a to make up this area.
201 void diff(const VoxelArea &a, std::list<VoxelArea> &result)
204 This can result in a maximum of 6 areas
207 // If a is an empty area, return the current area as a whole
208 if(a.getExtent() == v3s16(0,0,0))
211 if(b.getVolume() != 0)
218 // Take back area, XY inclusive
220 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
221 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
222 VoxelArea b(min, max);
223 if(b.getVolume() != 0)
227 // Take front area, XY inclusive
229 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
230 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
231 VoxelArea b(min, max);
232 if(b.getVolume() != 0)
236 // Take top area, X inclusive
238 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
239 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
240 VoxelArea b(min, max);
241 if(b.getVolume() != 0)
245 // Take bottom area, X inclusive
247 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
248 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
249 VoxelArea b(min, max);
250 if(b.getVolume() != 0)
254 // Take left area, non-inclusive
256 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
257 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
258 VoxelArea b(min, max);
259 if(b.getVolume() != 0)
263 // Take right area, non-inclusive
265 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
266 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
267 VoxelArea b(min, max);
268 if(b.getVolume() != 0)
275 Translates position from virtual coordinates to array index
277 s32 index(s16 x, s16 y, s16 z) const
279 v3s16 em = getExtent();
281 s32 i = (s32)(z-off.Z)*em.Y*em.X + (y-off.Y)*em.X + (x-off.X);
282 //dstream<<" i("<<x<<","<<y<<","<<z<<")="<<i<<" ";
285 s32 index(v3s16 p) const
287 return index(p.X, p.Y, p.Z);
290 // Translate index in the X coordinate
291 void add_x(const v3s16 &extent, u32 &i, s16 a)
295 // Translate index in the Y coordinate
296 void add_y(const v3s16 &extent, u32 &i, s16 a)
300 // Translate index in the Z coordinate
301 void add_z(const v3s16 &extent, u32 &i, s16 a)
303 i += a * extent.X*extent.Y;
305 // Translate index in space
306 void add_p(const v3s16 &extent, u32 &i, v3s16 a)
308 i += a.Z*extent.X*extent.Y + a.Y*extent.X + a.X;
312 Print method for debugging
314 void print(std::ostream &o) const
316 v3s16 e = getExtent();
324 <<"="<<e.X<<"x"<<e.Y<<"x"<<e.Z<<"="<<getVolume();
327 // Edges are inclusive
333 #define VOXELFLAG_UNUSED (1<<0)
334 // no data about that node
335 #define VOXELFLAG_NO_DATA (1<<1)
336 // Algorithm-dependent
337 #define VOXELFLAG_CHECKED1 (1<<2)
338 // Algorithm-dependent
339 #define VOXELFLAG_CHECKED2 (1<<3)
340 // Algorithm-dependent
341 #define VOXELFLAG_CHECKED3 (1<<4)
342 // Algorithm-dependent
343 #define VOXELFLAG_CHECKED4 (1<<5)
349 VOXELPRINT_WATERPRESSURE,
350 VOXELPRINT_LIGHT_DAY,
353 class VoxelManipulator /*: public NodeContainer*/
357 virtual ~VoxelManipulator();
360 Virtuals from NodeContainer
362 /*virtual u16 nodeContainerId() const
364 return NODECONTAINER_ID_VOXELMANIPULATOR;
366 bool isValidPosition(v3s16 p)
369 return !(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA);
373 These are a bit slow and shouldn't be used internally.
374 Use m_data[m_area.index(p)] instead.
376 MapNode getNode(v3s16 p)
378 VoxelArea voxel_area(p);
381 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
383 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
384 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
385 <<", index="<<m_area.index(p)
386 <<", flags="<<(int)m_flags[m_area.index(p)]
387 <<" is inexistent"<<std::endl;*/
388 throw InvalidPositionException
389 ("VoxelManipulator: getNode: inexistent");
392 return m_data[m_area.index(p)];
394 MapNode getNodeNoEx(v3s16 p)
396 VoxelArea voxel_area(p);
399 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
401 return MapNode(CONTENT_IGNORE);
404 return m_data[m_area.index(p)];
406 MapNode getNodeNoExNoEmerge(v3s16 p)
408 if(m_area.contains(p) == false)
409 return MapNode(CONTENT_IGNORE);
410 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
411 return MapNode(CONTENT_IGNORE);
412 return m_data[m_area.index(p)];
414 // Stuff explodes if non-emerged area is touched with this.
415 // Emerge first, and check VOXELFLAG_NO_DATA if appropriate.
416 MapNode & getNodeRefUnsafe(v3s16 p)
418 return m_data[m_area.index(p)];
420 u8 & getFlagsRefUnsafe(v3s16 p)
422 return m_flags[m_area.index(p)];
426 return m_area.contains(p) &&
427 !(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA);
429 MapNode & getNodeRef(v3s16 p)
431 VoxelArea voxel_area(p);
433 if(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA)
435 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
436 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
437 <<", index="<<m_area.index(p)
438 <<", flags="<<(int)getFlagsRefUnsafe(p)
439 <<" is inexistent"<<std::endl;*/
440 throw InvalidPositionException
441 ("VoxelManipulator: getNode: inexistent");
443 return getNodeRefUnsafe(p);
445 void setNode(v3s16 p, const MapNode &n)
447 VoxelArea voxel_area(p);
450 m_data[m_area.index(p)] = n;
451 m_flags[m_area.index(p)] &= ~VOXELFLAG_NO_DATA;
453 // TODO: Should be removed and replaced with setNode
454 void setNodeNoRef(v3s16 p, const MapNode &n)
459 /*void setExists(VoxelArea a)
462 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
463 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
464 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
466 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_NO_DATA;
470 /*MapNode & operator[](v3s16 p)
472 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
473 if(isValidPosition(p) == false)
474 addArea(VoxelArea(p));
476 return m_data[m_area.index(p)];
480 Set stuff if available without an emerge.
481 Return false if failed.
482 This is convenient but slower than playing around directly
483 with the m_data table with indices.
485 bool setNodeNoEmerge(v3s16 p, MapNode n)
487 if(m_area.contains(p) == false)
489 m_data[m_area.index(p)] = n;
492 bool setNodeNoEmerge(s32 i, MapNode n)
494 if(m_area.contains(i) == false)
499 /*bool setContentNoEmerge(v3s16 p, u8 c)
501 if(isValidPosition(p) == false)
503 m_data[m_area.index(p)].d = c;
510 virtual void clear();
512 void print(std::ostream &o, INodeDefManager *nodemgr,
513 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
515 void addArea(const VoxelArea &area);
518 Copy data and set flags to 0
519 dst_area.getExtent() <= src_area.getExtent()
521 void copyFrom(MapNode *src, const VoxelArea& src_area,
522 v3s16 from_pos, v3s16 to_pos, v3s16 size);
525 void copyTo(MapNode *dst, const VoxelArea& dst_area,
526 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
532 void clearFlag(u8 flag);
534 // TODO: Move to voxelalgorithms.h
536 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
537 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
538 void unspreadLight(enum LightBank bank,
539 std::map<v3s16, u8> & from_nodes,
540 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
542 void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
543 void spreadLight(enum LightBank bank,
544 std::set<v3s16> & from_nodes, INodeDefManager *nodemgr);
555 The area that is stored in m_data.
556 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
557 MaxEdge is 1 higher than maximum allowed position
562 NULL if data size is 0 (extent (0,0,0))
563 Data is stored as [z*h*w + y*h + x]
572 //TODO: Use these or remove them
573 //TODO: Would these make any speed improvement?
574 //bool m_pressure_route_valid;
575 //v3s16 m_pressure_route_surface;
580 //bool m_disable_water_climb;