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)
216 assert(contains(a)); // pre-condition
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(const v3s16 &p)
418 return m_data[m_area.index(p)];
421 const MapNode & getNodeRefUnsafeCheckFlags(const v3s16 &p)
423 s32 index = m_area.index(p);
425 if (m_flags[index] & VOXELFLAG_NO_DATA)
426 return ContentIgnoreNode;
428 return m_data[index];
431 u8 & getFlagsRefUnsafe(v3s16 p)
433 return m_flags[m_area.index(p)];
437 return m_area.contains(p) &&
438 !(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA);
440 MapNode & getNodeRef(v3s16 p)
442 VoxelArea voxel_area(p);
444 if(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA)
446 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
447 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
448 <<", index="<<m_area.index(p)
449 <<", flags="<<(int)getFlagsRefUnsafe(p)
450 <<" is inexistent"<<std::endl;*/
451 throw InvalidPositionException
452 ("VoxelManipulator: getNode: inexistent");
454 return getNodeRefUnsafe(p);
456 void setNode(v3s16 p, const MapNode &n)
458 VoxelArea voxel_area(p);
461 m_data[m_area.index(p)] = n;
462 m_flags[m_area.index(p)] &= ~VOXELFLAG_NO_DATA;
464 // TODO: Should be removed and replaced with setNode
465 void setNodeNoRef(v3s16 p, const MapNode &n)
470 /*void setExists(VoxelArea a)
473 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
474 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
475 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
477 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_NO_DATA;
481 /*MapNode & operator[](v3s16 p)
483 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
484 if(isValidPosition(p) == false)
485 addArea(VoxelArea(p));
487 return m_data[m_area.index(p)];
491 Set stuff if available without an emerge.
492 Return false if failed.
493 This is convenient but slower than playing around directly
494 with the m_data table with indices.
496 bool setNodeNoEmerge(v3s16 p, MapNode n)
498 if(m_area.contains(p) == false)
500 m_data[m_area.index(p)] = n;
503 bool setNodeNoEmerge(s32 i, MapNode n)
505 if(m_area.contains(i) == false)
510 /*bool setContentNoEmerge(v3s16 p, u8 c)
512 if(isValidPosition(p) == false)
514 m_data[m_area.index(p)].d = c;
521 virtual void clear();
523 void print(std::ostream &o, INodeDefManager *nodemgr,
524 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
526 void addArea(const VoxelArea &area);
529 Copy data and set flags to 0
530 dst_area.getExtent() <= src_area.getExtent()
532 void copyFrom(MapNode *src, const VoxelArea& src_area,
533 v3s16 from_pos, v3s16 to_pos, v3s16 size);
536 void copyTo(MapNode *dst, const VoxelArea& dst_area,
537 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
543 void clearFlag(u8 flag);
545 // TODO: Move to voxelalgorithms.h
547 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
548 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
549 void unspreadLight(enum LightBank bank,
550 std::map<v3s16, u8> & from_nodes,
551 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
553 void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
554 void spreadLight(enum LightBank bank,
555 std::set<v3s16> & from_nodes, INodeDefManager *nodemgr);
566 The area that is stored in m_data.
567 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
568 MaxEdge is 1 higher than maximum allowed position
573 NULL if data size is 0 (extent (0,0,0))
574 Data is stored as [z*h*w + y*h + x]
583 static const MapNode ContentIgnoreNode;
585 //TODO: Use these or remove them
586 //TODO: Would these make any speed improvement?
587 //bool m_pressure_route_valid;
588 //v3s16 m_pressure_route_surface;
593 //bool m_disable_water_climb;