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"
30 class INodeDefManager;
37 A fast voxel manipulator class.
39 In normal operation, it fetches more map when it is requested.
40 It can also be used so that all allowed area is fetched at the
41 start, using ManualMapVoxelManipulator.
49 extern u32 emerge_time;
50 extern u32 emerge_load_time;
53 This class resembles aabbox3d<s16> a lot, but has inclusive
54 edges for saner handling of integer sizes
59 // Starts as zero sized
65 VoxelArea(v3s16 min_edge, v3s16 max_edge):
80 void addArea(VoxelArea &a)
82 if(getExtent() == v3s16(0,0,0))
87 if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
88 if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
89 if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
90 if(a.MaxEdge.X > MaxEdge.X) MaxEdge.X = a.MaxEdge.X;
91 if(a.MaxEdge.Y > MaxEdge.Y) MaxEdge.Y = a.MaxEdge.Y;
92 if(a.MaxEdge.Z > MaxEdge.Z) MaxEdge.Z = a.MaxEdge.Z;
94 void addPoint(v3s16 p)
96 if(getExtent() == v3s16(0,0,0))
102 if(p.X < MinEdge.X) MinEdge.X = p.X;
103 if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
104 if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
105 if(p.X > MaxEdge.X) MaxEdge.X = p.X;
106 if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
107 if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
117 /*void operator+=(v3s16 off)
123 void operator-=(v3s16 off)
133 v3s16 getExtent() const
135 return MaxEdge - MinEdge + v3s16(1,1,1);
137 s32 getVolume() const
139 v3s16 e = getExtent();
140 return (s32)e.X * (s32)e.Y * (s32)e.Z;
142 bool contains(const VoxelArea &a) const
144 // No area contains an empty area
145 // NOTE: Algorithms depend on this, so do not change.
146 if(a.getExtent() == v3s16(0,0,0))
150 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
151 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
152 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
155 bool contains(v3s16 p) const
158 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
159 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
160 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
163 bool contains(s32 i) const
165 return (i >= 0 && i < getVolume());
167 bool operator==(const VoxelArea &other) const
169 return (MinEdge == other.MinEdge
170 && MaxEdge == other.MaxEdge);
173 VoxelArea operator+(v3s16 off) const
175 return VoxelArea(MinEdge+off, MaxEdge+off);
178 VoxelArea operator-(v3s16 off) const
180 return VoxelArea(MinEdge-off, MaxEdge-off);
184 Returns 0-6 non-overlapping areas that can be added to
185 a to make up this area.
189 void diff(const VoxelArea &a, core::list<VoxelArea> &result)
192 This can result in a maximum of 6 areas
195 // If a is an empty area, return the current area as a whole
196 if(a.getExtent() == v3s16(0,0,0))
199 if(b.getVolume() != 0)
206 // Take back area, XY inclusive
208 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
209 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
210 VoxelArea b(min, max);
211 if(b.getVolume() != 0)
215 // Take front area, XY inclusive
217 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
218 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
219 VoxelArea b(min, max);
220 if(b.getVolume() != 0)
224 // Take top area, X inclusive
226 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
227 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
228 VoxelArea b(min, max);
229 if(b.getVolume() != 0)
233 // Take bottom area, X inclusive
235 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
236 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
237 VoxelArea b(min, max);
238 if(b.getVolume() != 0)
242 // Take left area, non-inclusive
244 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
245 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
246 VoxelArea b(min, max);
247 if(b.getVolume() != 0)
251 // Take right area, non-inclusive
253 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
254 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
255 VoxelArea b(min, max);
256 if(b.getVolume() != 0)
263 Translates position from virtual coordinates to array index
265 s32 index(s16 x, s16 y, s16 z) const
267 v3s16 em = getExtent();
269 s32 i = (s32)(z-off.Z)*em.Y*em.X + (y-off.Y)*em.X + (x-off.X);
270 //dstream<<" i("<<x<<","<<y<<","<<z<<")="<<i<<" ";
273 s32 index(v3s16 p) const
275 return index(p.X, p.Y, p.Z);
278 // Translate index in the X coordinate
279 void add_x(const v3s16 &extent, u32 &i, s16 a)
283 // Translate index in the Y coordinate
284 void add_y(const v3s16 &extent, u32 &i, s16 a)
288 // Translate index in the Z coordinate
289 void add_z(const v3s16 &extent, u32 &i, s16 a)
291 i += a * extent.X*extent.Y;
293 // Translate index in space
294 void add_p(const v3s16 &extent, u32 &i, v3s16 a)
296 i += a.Z*extent.X*extent.Y + a.Y*extent.X + a.X;
300 Print method for debugging
302 void print(std::ostream &o) const
304 v3s16 e = getExtent();
312 <<"="<<e.X<<"x"<<e.Y<<"x"<<e.Z<<"="<<getVolume();
315 // Edges are inclusive
320 // Hasn't been copied from source (emerged)
321 #define VOXELFLAG_NOT_LOADED (1<<0)
322 // Checked as being inexistent in source
323 #define VOXELFLAG_INEXISTENT (1<<1)
324 // Algorithm-dependent
325 #define VOXELFLAG_CHECKED1 (1<<2)
326 // Algorithm-dependent
327 #define VOXELFLAG_CHECKED2 (1<<3)
328 // Algorithm-dependent
329 #define VOXELFLAG_CHECKED3 (1<<4)
330 // Algorithm-dependent
331 #define VOXELFLAG_CHECKED4 (1<<5)
337 VOXELPRINT_WATERPRESSURE,
338 VOXELPRINT_LIGHT_DAY,
341 class VoxelManipulator /*: public NodeContainer*/
345 virtual ~VoxelManipulator();
348 Virtuals from NodeContainer
350 /*virtual u16 nodeContainerId() const
352 return NODECONTAINER_ID_VOXELMANIPULATOR;
354 bool isValidPosition(v3s16 p)
357 return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT);
361 These are a bit slow and shouldn't be used internally.
362 Use m_data[m_area.index(p)] instead.
364 MapNode getNode(v3s16 p)
368 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
370 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
371 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
372 <<", index="<<m_area.index(p)
373 <<", flags="<<(int)m_flags[m_area.index(p)]
374 <<" is inexistent"<<std::endl;*/
375 throw InvalidPositionException
376 ("VoxelManipulator: getNode: inexistent");
379 return m_data[m_area.index(p)];
381 MapNode getNodeNoEx(v3s16 p)
385 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
387 return MapNode(CONTENT_IGNORE);
390 return m_data[m_area.index(p)];
392 MapNode getNodeNoExNoEmerge(v3s16 p)
394 if(m_area.contains(p) == false)
395 return MapNode(CONTENT_IGNORE);
396 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
397 return MapNode(CONTENT_IGNORE);
398 return m_data[m_area.index(p)];
400 // Stuff explodes if non-emerged area is touched with this.
401 // Emerge first, and check VOXELFLAG_INEXISTENT if appropriate.
402 MapNode & getNodeRefUnsafe(v3s16 p)
404 return m_data[m_area.index(p)];
406 u8 & getFlagsRefUnsafe(v3s16 p)
408 return m_flags[m_area.index(p)];
412 return m_area.contains(p) &&
413 !(getFlagsRefUnsafe(p) & VOXELFLAG_INEXISTENT);
415 MapNode & getNodeRef(v3s16 p)
418 if(getFlagsRefUnsafe(p) & VOXELFLAG_INEXISTENT)
420 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
421 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
422 <<", index="<<m_area.index(p)
423 <<", flags="<<(int)getFlagsRefUnsafe(p)
424 <<" is inexistent"<<std::endl;*/
425 throw InvalidPositionException
426 ("VoxelManipulator: getNode: inexistent");
428 return getNodeRefUnsafe(p);
430 void setNode(v3s16 p, const MapNode &n)
434 m_data[m_area.index(p)] = n;
435 m_flags[m_area.index(p)] &= ~VOXELFLAG_INEXISTENT;
436 m_flags[m_area.index(p)] &= ~VOXELFLAG_NOT_LOADED;
438 // TODO: Should be removed and replaced with setNode
439 void setNodeNoRef(v3s16 p, const MapNode &n)
444 /*void setExists(VoxelArea a)
447 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
448 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
449 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
451 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_INEXISTENT;
455 /*MapNode & operator[](v3s16 p)
457 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
458 if(isValidPosition(p) == false)
459 emerge(VoxelArea(p));
461 return m_data[m_area.index(p)];
465 Set stuff if available without an emerge.
466 Return false if failed.
467 This is convenient but slower than playing around directly
468 with the m_data table with indices.
470 bool setNodeNoEmerge(v3s16 p, MapNode n)
472 if(m_area.contains(p) == false)
474 m_data[m_area.index(p)] = n;
477 bool setNodeNoEmerge(s32 i, MapNode n)
479 if(m_area.contains(i) == false)
484 /*bool setContentNoEmerge(v3s16 p, u8 c)
486 if(isValidPosition(p) == false)
488 m_data[m_area.index(p)].d = c;
495 virtual void clear();
497 void print(std::ostream &o, INodeDefManager *nodemgr,
498 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
500 void addArea(VoxelArea area);
503 Copy data and set flags to 0
504 dst_area.getExtent() <= src_area.getExtent()
506 void copyFrom(MapNode *src, VoxelArea src_area,
507 v3s16 from_pos, v3s16 to_pos, v3s16 size);
510 void copyTo(MapNode *dst, VoxelArea dst_area,
511 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
517 void clearFlag(u8 flag);
519 // TODO: Move to voxelalgorithms.h
521 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
522 core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
523 void unspreadLight(enum LightBank bank,
524 core::map<v3s16, u8> & from_nodes,
525 core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
527 void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
528 void spreadLight(enum LightBank bank,
529 core::map<v3s16, bool> & from_nodes, INodeDefManager *nodemgr);
536 Get the contents of the requested area from somewhere.
537 Shall touch only nodes that have VOXELFLAG_NOT_LOADED
538 Shall reset VOXELFLAG_NOT_LOADED
540 If not found from source, add with VOXELFLAG_INEXISTENT
542 virtual void emerge(VoxelArea a, s32 caller_id=-1)
544 //dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
546 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
547 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
548 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
550 s32 i = m_area.index(x,y,z);
551 // Don't touch nodes that have already been loaded
552 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
554 m_flags[i] = VOXELFLAG_INEXISTENT;
563 The area that is stored in m_data.
564 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
565 MaxEdge is 1 higher than maximum allowed position
570 NULL if data size is 0 (extent (0,0,0))
571 Data is stored as [z*h*w + y*h + x]
580 //TODO: Use these or remove them
581 //TODO: Would these make any speed improvement?
582 //bool m_pressure_route_valid;
583 //v3s16 m_pressure_route_surface;
588 //bool m_disable_water_climb;