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)
85 if(getExtent() == v3s16(0,0,0))
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)
99 if(getExtent() == v3s16(0,0,0))
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);
140 s32 getVolume() const
142 v3s16 e = getExtent();
143 return (s32)e.X * (s32)e.Y * (s32)e.Z;
145 bool contains(const VoxelArea &a) const
147 // No area contains an empty area
148 // NOTE: Algorithms depend on this, so do not change.
149 if(a.getExtent() == v3s16(0,0,0))
153 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
154 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
155 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
158 bool contains(v3s16 p) const
161 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
162 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
163 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
166 bool contains(s32 i) const
168 return (i >= 0 && i < getVolume());
170 bool operator==(const VoxelArea &other) const
172 return (MinEdge == other.MinEdge
173 && MaxEdge == other.MaxEdge);
176 VoxelArea operator+(v3s16 off) const
178 return VoxelArea(MinEdge+off, MaxEdge+off);
181 VoxelArea operator-(v3s16 off) const
183 return VoxelArea(MinEdge-off, MaxEdge-off);
187 Returns 0-6 non-overlapping areas that can be added to
188 a to make up this area.
192 void diff(const VoxelArea &a, std::list<VoxelArea> &result)
195 This can result in a maximum of 6 areas
198 // If a is an empty area, return the current area as a whole
199 if(a.getExtent() == v3s16(0,0,0))
202 if(b.getVolume() != 0)
209 // Take back area, XY inclusive
211 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
212 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
213 VoxelArea b(min, max);
214 if(b.getVolume() != 0)
218 // Take front area, XY inclusive
220 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
221 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
222 VoxelArea b(min, max);
223 if(b.getVolume() != 0)
227 // Take top area, X inclusive
229 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
230 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
231 VoxelArea b(min, max);
232 if(b.getVolume() != 0)
236 // Take bottom area, X inclusive
238 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
239 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
240 VoxelArea b(min, max);
241 if(b.getVolume() != 0)
245 // Take left area, non-inclusive
247 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
248 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
249 VoxelArea b(min, max);
250 if(b.getVolume() != 0)
254 // Take right area, non-inclusive
256 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
257 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
258 VoxelArea b(min, max);
259 if(b.getVolume() != 0)
266 Translates position from virtual coordinates to array index
268 s32 index(s16 x, s16 y, s16 z) const
270 v3s16 em = getExtent();
272 s32 i = (s32)(z-off.Z)*em.Y*em.X + (y-off.Y)*em.X + (x-off.X);
273 //dstream<<" i("<<x<<","<<y<<","<<z<<")="<<i<<" ";
276 s32 index(v3s16 p) const
278 return index(p.X, p.Y, p.Z);
281 // Translate index in the X coordinate
282 void add_x(const v3s16 &extent, u32 &i, s16 a)
286 // Translate index in the Y coordinate
287 void add_y(const v3s16 &extent, u32 &i, s16 a)
291 // Translate index in the Z coordinate
292 void add_z(const v3s16 &extent, u32 &i, s16 a)
294 i += a * extent.X*extent.Y;
296 // Translate index in space
297 void add_p(const v3s16 &extent, u32 &i, v3s16 a)
299 i += a.Z*extent.X*extent.Y + a.Y*extent.X + a.X;
303 Print method for debugging
305 void print(std::ostream &o) const
307 v3s16 e = getExtent();
315 <<"="<<e.X<<"x"<<e.Y<<"x"<<e.Z<<"="<<getVolume();
318 // Edges are inclusive
324 #define VOXELFLAG_UNUSED (1<<0)
325 // no data about that node
326 #define VOXELFLAG_NO_DATA (1<<1)
327 // Algorithm-dependent
328 #define VOXELFLAG_CHECKED1 (1<<2)
329 // Algorithm-dependent
330 #define VOXELFLAG_CHECKED2 (1<<3)
331 // Algorithm-dependent
332 #define VOXELFLAG_CHECKED3 (1<<4)
333 // Algorithm-dependent
334 #define VOXELFLAG_CHECKED4 (1<<5)
340 VOXELPRINT_WATERPRESSURE,
341 VOXELPRINT_LIGHT_DAY,
344 class VoxelManipulator /*: public NodeContainer*/
348 virtual ~VoxelManipulator();
351 Virtuals from NodeContainer
353 /*virtual u16 nodeContainerId() const
355 return NODECONTAINER_ID_VOXELMANIPULATOR;
357 bool isValidPosition(v3s16 p)
360 return !(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA);
364 These are a bit slow and shouldn't be used internally.
365 Use m_data[m_area.index(p)] instead.
367 MapNode getNode(v3s16 p)
369 VoxelArea voxel_area(p);
372 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
374 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
375 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
376 <<", index="<<m_area.index(p)
377 <<", flags="<<(int)m_flags[m_area.index(p)]
378 <<" is inexistent"<<std::endl;*/
379 throw InvalidPositionException
380 ("VoxelManipulator: getNode: inexistent");
383 return m_data[m_area.index(p)];
385 MapNode getNodeNoEx(v3s16 p)
387 VoxelArea voxel_area(p);
390 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
392 return MapNode(CONTENT_IGNORE);
395 return m_data[m_area.index(p)];
397 MapNode getNodeNoExNoEmerge(v3s16 p)
399 if(m_area.contains(p) == false)
400 return MapNode(CONTENT_IGNORE);
401 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
402 return MapNode(CONTENT_IGNORE);
403 return m_data[m_area.index(p)];
405 // Stuff explodes if non-emerged area is touched with this.
406 // Emerge first, and check VOXELFLAG_NO_DATA if appropriate.
407 MapNode & getNodeRefUnsafe(v3s16 p)
409 return m_data[m_area.index(p)];
411 u8 & getFlagsRefUnsafe(v3s16 p)
413 return m_flags[m_area.index(p)];
417 return m_area.contains(p) &&
418 !(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA);
420 MapNode & getNodeRef(v3s16 p)
422 VoxelArea voxel_area(p);
424 if(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA)
426 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
427 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
428 <<", index="<<m_area.index(p)
429 <<", flags="<<(int)getFlagsRefUnsafe(p)
430 <<" is inexistent"<<std::endl;*/
431 throw InvalidPositionException
432 ("VoxelManipulator: getNode: inexistent");
434 return getNodeRefUnsafe(p);
436 void setNode(v3s16 p, const MapNode &n)
438 VoxelArea voxel_area(p);
441 m_data[m_area.index(p)] = n;
442 m_flags[m_area.index(p)] &= ~VOXELFLAG_NO_DATA;
444 // TODO: Should be removed and replaced with setNode
445 void setNodeNoRef(v3s16 p, const MapNode &n)
450 /*void setExists(VoxelArea a)
453 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
454 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
455 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
457 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_NO_DATA;
461 /*MapNode & operator[](v3s16 p)
463 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
464 if(isValidPosition(p) == false)
465 addArea(VoxelArea(p));
467 return m_data[m_area.index(p)];
471 Set stuff if available without an emerge.
472 Return false if failed.
473 This is convenient but slower than playing around directly
474 with the m_data table with indices.
476 bool setNodeNoEmerge(v3s16 p, MapNode n)
478 if(m_area.contains(p) == false)
480 m_data[m_area.index(p)] = n;
483 bool setNodeNoEmerge(s32 i, MapNode n)
485 if(m_area.contains(i) == false)
490 /*bool setContentNoEmerge(v3s16 p, u8 c)
492 if(isValidPosition(p) == false)
494 m_data[m_area.index(p)].d = c;
501 virtual void clear();
503 void print(std::ostream &o, INodeDefManager *nodemgr,
504 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
506 void addArea(const VoxelArea &area);
509 Copy data and set flags to 0
510 dst_area.getExtent() <= src_area.getExtent()
512 void copyFrom(MapNode *src, const VoxelArea& src_area,
513 v3s16 from_pos, v3s16 to_pos, v3s16 size);
516 void copyTo(MapNode *dst, const VoxelArea& dst_area,
517 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
523 void clearFlag(u8 flag);
525 // TODO: Move to voxelalgorithms.h
527 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
528 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
529 void unspreadLight(enum LightBank bank,
530 std::map<v3s16, u8> & from_nodes,
531 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
533 void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
534 void spreadLight(enum LightBank bank,
535 std::set<v3s16> & from_nodes, INodeDefManager *nodemgr);
546 The area that is stored in m_data.
547 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
548 MaxEdge is 1 higher than maximum allowed position
553 NULL if data size is 0 (extent (0,0,0))
554 Data is stored as [z*h*w + y*h + x]
563 //TODO: Use these or remove them
564 //TODO: Would these make any speed improvement?
565 //bool m_pressure_route_valid;
566 //v3s16 m_pressure_route_surface;
571 //bool m_disable_water_climb;