3 Copyright (C) 2010 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
15 You should have received a copy of the GNU 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"
28 class INodeDefManager;
35 A fast voxel manipulator class.
37 In normal operation, it fetches more map when it is requested.
38 It can also be used so that all allowed area is fetched at the
39 start, using ManualMapVoxelManipulator.
47 extern u32 emerge_time;
48 extern u32 emerge_load_time;
51 This class resembles aabbox3d<s16> a lot, but has inclusive
52 edges for saner handling of integer sizes
57 // Starts as zero sized
63 VoxelArea(v3s16 min_edge, v3s16 max_edge):
78 void addArea(VoxelArea &a)
80 if(getExtent() == v3s16(0,0,0))
85 if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
86 if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
87 if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
88 if(a.MaxEdge.X > MaxEdge.X) MaxEdge.X = a.MaxEdge.X;
89 if(a.MaxEdge.Y > MaxEdge.Y) MaxEdge.Y = a.MaxEdge.Y;
90 if(a.MaxEdge.Z > MaxEdge.Z) MaxEdge.Z = a.MaxEdge.Z;
92 void addPoint(v3s16 p)
94 if(getExtent() == v3s16(0,0,0))
100 if(p.X < MinEdge.X) MinEdge.X = p.X;
101 if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
102 if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
103 if(p.X > MaxEdge.X) MaxEdge.X = p.X;
104 if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
105 if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
115 /*void operator+=(v3s16 off)
121 void operator-=(v3s16 off)
131 v3s16 getExtent() const
133 return MaxEdge - MinEdge + v3s16(1,1,1);
135 s32 getVolume() const
137 v3s16 e = getExtent();
138 return (s32)e.X * (s32)e.Y * (s32)e.Z;
140 bool contains(const VoxelArea &a) const
142 // No area contains an empty area
143 // NOTE: Algorithms depend on this, so do not change.
144 if(a.getExtent() == v3s16(0,0,0))
148 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
149 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
150 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
153 bool contains(v3s16 p) const
156 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
157 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
158 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
161 bool contains(s32 i) const
163 return (i >= 0 && i < getVolume());
165 bool operator==(const VoxelArea &other) const
167 return (MinEdge == other.MinEdge
168 && MaxEdge == other.MaxEdge);
171 VoxelArea operator+(v3s16 off) const
173 return VoxelArea(MinEdge+off, MaxEdge+off);
176 VoxelArea operator-(v3s16 off) const
178 return VoxelArea(MinEdge-off, MaxEdge-off);
182 Returns 0-6 non-overlapping areas that can be added to
183 a to make up this area.
187 void diff(const VoxelArea &a, core::list<VoxelArea> &result)
190 This can result in a maximum of 6 areas
193 // If a is an empty area, return the current area as a whole
194 if(a.getExtent() == v3s16(0,0,0))
197 if(b.getVolume() != 0)
204 // Take back area, XY inclusive
206 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
207 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
208 VoxelArea b(min, max);
209 if(b.getVolume() != 0)
213 // Take front area, XY inclusive
215 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
216 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
217 VoxelArea b(min, max);
218 if(b.getVolume() != 0)
222 // Take top area, X inclusive
224 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
225 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
226 VoxelArea b(min, max);
227 if(b.getVolume() != 0)
231 // Take bottom area, X inclusive
233 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
234 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
235 VoxelArea b(min, max);
236 if(b.getVolume() != 0)
240 // Take left area, non-inclusive
242 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
243 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
244 VoxelArea b(min, max);
245 if(b.getVolume() != 0)
249 // Take right area, non-inclusive
251 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
252 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
253 VoxelArea b(min, max);
254 if(b.getVolume() != 0)
261 Translates position from virtual coordinates to array index
263 s32 index(s16 x, s16 y, s16 z) const
265 v3s16 em = getExtent();
267 s32 i = (s32)(z-off.Z)*em.Y*em.X + (y-off.Y)*em.X + (x-off.X);
268 //dstream<<" i("<<x<<","<<y<<","<<z<<")="<<i<<" ";
271 s32 index(v3s16 p) const
273 return index(p.X, p.Y, p.Z);
276 // Translate index in the X coordinate
277 void add_x(const v3s16 &extent, u32 &i, s16 a)
281 // Translate index in the Y coordinate
282 void add_y(const v3s16 &extent, u32 &i, s16 a)
286 // Translate index in the Z coordinate
287 void add_z(const v3s16 &extent, u32 &i, s16 a)
289 i += a * extent.X*extent.Y;
291 // Translate index in space
292 void add_p(const v3s16 &extent, u32 &i, v3s16 a)
294 i += a.Z*extent.X*extent.Y + a.Y*extent.X + a.X;
298 Print method for debugging
300 void print(std::ostream &o) const
302 v3s16 e = getExtent();
310 <<"="<<e.X<<"x"<<e.Y<<"x"<<e.Z<<"="<<getVolume();
313 // Edges are inclusive
318 // Hasn't been copied from source (emerged)
319 #define VOXELFLAG_NOT_LOADED (1<<0)
320 // Checked as being inexistent in source
321 #define VOXELFLAG_INEXISTENT (1<<1)
322 // Algorithm-dependent
323 #define VOXELFLAG_CHECKED1 (1<<2)
324 // Algorithm-dependent
325 #define VOXELFLAG_CHECKED2 (1<<3)
326 // Algorithm-dependent
327 #define VOXELFLAG_CHECKED3 (1<<4)
328 // Algorithm-dependent
329 #define VOXELFLAG_CHECKED4 (1<<5)
335 VOXELPRINT_WATERPRESSURE,
336 VOXELPRINT_LIGHT_DAY,
339 class VoxelManipulator /*: public NodeContainer*/
343 virtual ~VoxelManipulator();
346 Virtuals from NodeContainer
348 /*virtual u16 nodeContainerId() const
350 return NODECONTAINER_ID_VOXELMANIPULATOR;
352 bool isValidPosition(v3s16 p)
355 return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT);
359 These are a bit slow and shouldn't be used internally.
360 Use m_data[m_area.index(p)] instead.
362 MapNode getNode(v3s16 p)
366 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
368 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
369 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
370 <<", index="<<m_area.index(p)
371 <<", flags="<<(int)m_flags[m_area.index(p)]
372 <<" is inexistent"<<std::endl;*/
373 throw InvalidPositionException
374 ("VoxelManipulator: getNode: inexistent");
377 return m_data[m_area.index(p)];
379 MapNode getNodeNoEx(v3s16 p)
383 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
385 return MapNode(CONTENT_IGNORE);
388 return m_data[m_area.index(p)];
390 MapNode getNodeNoExNoEmerge(v3s16 p)
392 if(m_area.contains(p) == false)
393 return MapNode(CONTENT_IGNORE);
394 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
395 return MapNode(CONTENT_IGNORE);
396 return m_data[m_area.index(p)];
398 // Stuff explodes if non-emerged area is touched with this.
399 // Emerge first, and check VOXELFLAG_INEXISTENT if appropriate.
400 MapNode & getNodeRefUnsafe(v3s16 p)
402 return m_data[m_area.index(p)];
404 u8 & getFlagsRefUnsafe(v3s16 p)
406 return m_flags[m_area.index(p)];
410 return m_area.contains(p) &&
411 !(getFlagsRefUnsafe(p) & VOXELFLAG_INEXISTENT);
413 MapNode & getNodeRef(v3s16 p)
416 if(getFlagsRefUnsafe(p) & VOXELFLAG_INEXISTENT)
418 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
419 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
420 <<", index="<<m_area.index(p)
421 <<", flags="<<(int)getFlagsRefUnsafe(p)
422 <<" is inexistent"<<std::endl;*/
423 throw InvalidPositionException
424 ("VoxelManipulator: getNode: inexistent");
426 return getNodeRefUnsafe(p);
428 void setNode(v3s16 p, const MapNode &n)
432 m_data[m_area.index(p)] = n;
433 m_flags[m_area.index(p)] &= ~VOXELFLAG_INEXISTENT;
434 m_flags[m_area.index(p)] &= ~VOXELFLAG_NOT_LOADED;
436 // TODO: Should be removed and replaced with setNode
437 void setNodeNoRef(v3s16 p, const MapNode &n)
442 /*void setExists(VoxelArea a)
445 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
446 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
447 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
449 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_INEXISTENT;
453 /*MapNode & operator[](v3s16 p)
455 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
456 if(isValidPosition(p) == false)
457 emerge(VoxelArea(p));
459 return m_data[m_area.index(p)];
463 Set stuff if available without an emerge.
464 Return false if failed.
465 This is convenient but slower than playing around directly
466 with the m_data table with indices.
468 bool setNodeNoEmerge(v3s16 p, MapNode n)
470 if(m_area.contains(p) == false)
472 m_data[m_area.index(p)] = n;
475 bool setNodeNoEmerge(s32 i, MapNode n)
477 if(m_area.contains(i) == false)
482 /*bool setContentNoEmerge(v3s16 p, u8 c)
484 if(isValidPosition(p) == false)
486 m_data[m_area.index(p)].d = c;
493 virtual void clear();
495 void print(std::ostream &o, INodeDefManager *nodemgr,
496 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
498 void addArea(VoxelArea area);
501 Copy data and set flags to 0
502 dst_area.getExtent() <= src_area.getExtent()
504 void copyFrom(MapNode *src, VoxelArea src_area,
505 v3s16 from_pos, v3s16 to_pos, v3s16 size);
508 void copyTo(MapNode *dst, VoxelArea dst_area,
509 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
515 void clearFlag(u8 flag);
517 // TODO: Move to voxelalgorithms.h
519 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
520 core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
521 void unspreadLight(enum LightBank bank,
522 core::map<v3s16, u8> & from_nodes,
523 core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
525 void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
526 void spreadLight(enum LightBank bank,
527 core::map<v3s16, bool> & from_nodes, INodeDefManager *nodemgr);
534 Get the contents of the requested area from somewhere.
535 Shall touch only nodes that have VOXELFLAG_NOT_LOADED
536 Shall reset VOXELFLAG_NOT_LOADED
538 If not found from source, add with VOXELFLAG_INEXISTENT
540 virtual void emerge(VoxelArea a, s32 caller_id=-1)
542 //dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
544 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
545 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
546 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
548 s32 i = m_area.index(x,y,z);
549 // Don't touch nodes that have already been loaded
550 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
552 m_flags[i] = VOXELFLAG_INEXISTENT;
561 The area that is stored in m_data.
562 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
563 MaxEdge is 1 higher than maximum allowed position
568 NULL if data size is 0 (extent (0,0,0))
569 Data is stored as [z*h*w + y*h + x]
578 //TODO: Use these or remove them
579 //TODO: Would these make any speed improvement?
580 //bool m_pressure_route_valid;
581 //v3s16 m_pressure_route_surface;
586 //bool m_disable_water_climb;