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(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(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;
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)
371 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
373 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
374 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
375 <<", index="<<m_area.index(p)
376 <<", flags="<<(int)m_flags[m_area.index(p)]
377 <<" is inexistent"<<std::endl;*/
378 throw InvalidPositionException
379 ("VoxelManipulator: getNode: inexistent");
382 return m_data[m_area.index(p)];
384 MapNode getNodeNoEx(v3s16 p)
388 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
390 return MapNode(CONTENT_IGNORE);
393 return m_data[m_area.index(p)];
395 MapNode getNodeNoExNoEmerge(v3s16 p)
397 if(m_area.contains(p) == false)
398 return MapNode(CONTENT_IGNORE);
399 if(m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA)
400 return MapNode(CONTENT_IGNORE);
401 return m_data[m_area.index(p)];
403 // Stuff explodes if non-emerged area is touched with this.
404 // Emerge first, and check VOXELFLAG_NO_DATA if appropriate.
405 MapNode & getNodeRefUnsafe(v3s16 p)
407 return m_data[m_area.index(p)];
409 u8 & getFlagsRefUnsafe(v3s16 p)
411 return m_flags[m_area.index(p)];
415 return m_area.contains(p) &&
416 !(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA);
418 MapNode & getNodeRef(v3s16 p)
421 if(getFlagsRefUnsafe(p) & VOXELFLAG_NO_DATA)
423 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
424 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
425 <<", index="<<m_area.index(p)
426 <<", flags="<<(int)getFlagsRefUnsafe(p)
427 <<" is inexistent"<<std::endl;*/
428 throw InvalidPositionException
429 ("VoxelManipulator: getNode: inexistent");
431 return getNodeRefUnsafe(p);
433 void setNode(v3s16 p, const MapNode &n)
437 m_data[m_area.index(p)] = n;
438 m_flags[m_area.index(p)] &= ~VOXELFLAG_NO_DATA;
440 // TODO: Should be removed and replaced with setNode
441 void setNodeNoRef(v3s16 p, const MapNode &n)
446 /*void setExists(VoxelArea a)
449 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
450 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
451 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
453 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_NO_DATA;
457 /*MapNode & operator[](v3s16 p)
459 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
460 if(isValidPosition(p) == false)
461 addArea(VoxelArea(p));
463 return m_data[m_area.index(p)];
467 Set stuff if available without an emerge.
468 Return false if failed.
469 This is convenient but slower than playing around directly
470 with the m_data table with indices.
472 bool setNodeNoEmerge(v3s16 p, MapNode n)
474 if(m_area.contains(p) == false)
476 m_data[m_area.index(p)] = n;
479 bool setNodeNoEmerge(s32 i, MapNode n)
481 if(m_area.contains(i) == false)
486 /*bool setContentNoEmerge(v3s16 p, u8 c)
488 if(isValidPosition(p) == false)
490 m_data[m_area.index(p)].d = c;
497 virtual void clear();
499 void print(std::ostream &o, INodeDefManager *nodemgr,
500 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
502 void addArea(VoxelArea area);
505 Copy data and set flags to 0
506 dst_area.getExtent() <= src_area.getExtent()
508 void copyFrom(MapNode *src, const VoxelArea& src_area,
509 v3s16 from_pos, v3s16 to_pos, v3s16 size);
512 void copyTo(MapNode *dst, const VoxelArea& dst_area,
513 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
519 void clearFlag(u8 flag);
521 // TODO: Move to voxelalgorithms.h
523 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
524 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
525 void unspreadLight(enum LightBank bank,
526 std::map<v3s16, u8> & from_nodes,
527 std::set<v3s16> & light_sources, INodeDefManager *nodemgr);
529 void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
530 void spreadLight(enum LightBank bank,
531 std::set<v3s16> & from_nodes, INodeDefManager *nodemgr);
542 The area that is stored in m_data.
543 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
544 MaxEdge is 1 higher than maximum allowed position
549 NULL if data size is 0 (extent (0,0,0))
550 Data is stored as [z*h*w + y*h + x]
559 //TODO: Use these or remove them
560 //TODO: Would these make any speed improvement?
561 //bool m_pressure_route_valid;
562 //v3s16 m_pressure_route_surface;
567 //bool m_disable_water_climb;