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 "common_irrlicht.h"
33 A fast voxel manipulator class.
35 In normal operation, it fetches more map when it is requested.
36 It can also be used so that all allowed area is fetched at the
37 start, using ManualMapVoxelManipulator.
45 extern u32 emerge_time;
46 extern u32 emerge_load_time;
49 This class resembles aabbox3d<s16> a lot, but has inclusive
50 edges for saner handling of integer sizes
55 // Starts as zero sized
61 VoxelArea(v3s16 min_edge, v3s16 max_edge):
76 void addArea(VoxelArea &a)
78 if(getExtent() == v3s16(0,0,0))
83 if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
84 if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
85 if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
86 if(a.MaxEdge.X > MaxEdge.X) MaxEdge.X = a.MaxEdge.X;
87 if(a.MaxEdge.Y > MaxEdge.Y) MaxEdge.Y = a.MaxEdge.Y;
88 if(a.MaxEdge.Z > MaxEdge.Z) MaxEdge.Z = a.MaxEdge.Z;
90 void addPoint(v3s16 p)
92 if(getExtent() == v3s16(0,0,0))
98 if(p.X < MinEdge.X) MinEdge.X = p.X;
99 if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
100 if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
101 if(p.X > MaxEdge.X) MaxEdge.X = p.X;
102 if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
103 if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
113 /*void operator+=(v3s16 off)
119 void operator-=(v3s16 off)
129 v3s16 getExtent() const
131 return MaxEdge - MinEdge + v3s16(1,1,1);
133 s32 getVolume() const
135 v3s16 e = getExtent();
136 return (s32)e.X * (s32)e.Y * (s32)e.Z;
138 bool contains(const VoxelArea &a) const
140 // No area contains an empty area
141 // NOTE: Algorithms depend on this, so do not change.
142 if(a.getExtent() == v3s16(0,0,0))
146 a.MinEdge.X >= MinEdge.X && a.MaxEdge.X <= MaxEdge.X &&
147 a.MinEdge.Y >= MinEdge.Y && a.MaxEdge.Y <= MaxEdge.Y &&
148 a.MinEdge.Z >= MinEdge.Z && a.MaxEdge.Z <= MaxEdge.Z
151 bool contains(v3s16 p) const
154 p.X >= MinEdge.X && p.X <= MaxEdge.X &&
155 p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
156 p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
159 bool contains(s32 i) const
161 return (i >= 0 && i < getVolume());
163 bool operator==(const VoxelArea &other) const
165 return (MinEdge == other.MinEdge
166 && MaxEdge == other.MaxEdge);
169 VoxelArea operator+(v3s16 off) const
171 return VoxelArea(MinEdge+off, MaxEdge+off);
174 VoxelArea operator-(v3s16 off) const
176 return VoxelArea(MinEdge-off, MaxEdge-off);
180 Returns 0-6 non-overlapping areas that can be added to
181 a to make up this area.
185 void diff(const VoxelArea &a, core::list<VoxelArea> &result)
188 This can result in a maximum of 6 areas
191 // If a is an empty area, return the current area as a whole
192 if(a.getExtent() == v3s16(0,0,0))
195 if(b.getVolume() != 0)
202 // Take back area, XY inclusive
204 v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
205 v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
206 VoxelArea b(min, max);
207 if(b.getVolume() != 0)
211 // Take front area, XY inclusive
213 v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
214 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
215 VoxelArea b(min, max);
216 if(b.getVolume() != 0)
220 // Take top area, X inclusive
222 v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
223 v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
224 VoxelArea b(min, max);
225 if(b.getVolume() != 0)
229 // Take bottom area, X inclusive
231 v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
232 v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
233 VoxelArea b(min, max);
234 if(b.getVolume() != 0)
238 // Take left area, non-inclusive
240 v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
241 v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
242 VoxelArea b(min, max);
243 if(b.getVolume() != 0)
247 // Take right area, non-inclusive
249 v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
250 v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
251 VoxelArea b(min, max);
252 if(b.getVolume() != 0)
259 Translates position from virtual coordinates to array index
261 s32 index(s16 x, s16 y, s16 z) const
263 v3s16 em = getExtent();
265 s32 i = (s32)(z-off.Z)*em.Y*em.X + (y-off.Y)*em.X + (x-off.X);
266 //dstream<<" i("<<x<<","<<y<<","<<z<<")="<<i<<" ";
269 s32 index(v3s16 p) const
271 return index(p.X, p.Y, p.Z);
274 // Translate index in the X coordinate
275 void add_x(const v3s16 &extent, u32 &i, s16 a)
279 // Translate index in the Y coordinate
280 void add_y(const v3s16 &extent, u32 &i, s16 a)
284 // Translate index in the Z coordinate
285 void add_z(const v3s16 &extent, u32 &i, s16 a)
287 i += a * extent.X*extent.Y;
289 // Translate index in space
290 void add_p(const v3s16 &extent, u32 &i, v3s16 a)
292 i += a.Z*extent.X*extent.Y + a.Y*extent.X + a.X;
296 Print method for debugging
298 void print(std::ostream &o) const
300 v3s16 e = getExtent();
308 <<"="<<e.X<<"x"<<e.Y<<"x"<<e.Z<<"="<<getVolume();
311 // Edges are inclusive
316 // Hasn't been copied from source (emerged)
317 #define VOXELFLAG_NOT_LOADED (1<<0)
318 // Checked as being inexistent in source
319 #define VOXELFLAG_INEXISTENT (1<<1)
320 // Algorithm-dependent
321 #define VOXELFLAG_CHECKED1 (1<<2)
322 // Algorithm-dependent
323 #define VOXELFLAG_CHECKED2 (1<<3)
324 // Algorithm-dependent
325 #define VOXELFLAG_CHECKED3 (1<<4)
326 // Algorithm-dependent
327 #define VOXELFLAG_CHECKED4 (1<<5)
333 VOXELPRINT_WATERPRESSURE,
336 class VoxelManipulator /*: public NodeContainer*/
340 virtual ~VoxelManipulator();
343 Virtuals from NodeContainer
345 /*virtual u16 nodeContainerId() const
347 return NODECONTAINER_ID_VOXELMANIPULATOR;
349 bool isValidPosition(v3s16 p)
352 return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT);
356 These are a bit slow and shouldn't be used internally.
357 Use m_data[m_area.index(p)] instead.
359 MapNode getNode(v3s16 p)
363 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
365 dstream<<"EXCEPT: VoxelManipulator::getNode(): "
366 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
367 <<", index="<<m_area.index(p)
368 <<", flags="<<(int)m_flags[m_area.index(p)]
369 <<" is inexistent"<<std::endl;
370 throw InvalidPositionException
371 ("VoxelManipulator: getNode: inexistent");
374 return m_data[m_area.index(p)];
376 MapNode getNodeNoEx(v3s16 p)
380 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
382 return MapNode(CONTENT_IGNORE);
385 return m_data[m_area.index(p)];
387 MapNode & getNodeRef(v3s16 p)
391 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
393 dstream<<"EXCEPT: VoxelManipulator::getNode(): "
394 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
395 <<", index="<<m_area.index(p)
396 <<", flags="<<(int)m_flags[m_area.index(p)]
397 <<" is inexistent"<<std::endl;
398 throw InvalidPositionException
399 ("VoxelManipulator: getNode: inexistent");
402 return m_data[m_area.index(p)];
404 void setNode(v3s16 p, MapNode &n)
408 m_data[m_area.index(p)] = n;
409 m_flags[m_area.index(p)] &= ~VOXELFLAG_INEXISTENT;
410 m_flags[m_area.index(p)] &= ~VOXELFLAG_NOT_LOADED;
412 void setNodeNoRef(v3s16 p, MapNode n)
417 /*void setExists(VoxelArea a)
420 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
421 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
422 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
424 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_INEXISTENT;
428 /*MapNode & operator[](v3s16 p)
430 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
431 if(isValidPosition(p) == false)
432 emerge(VoxelArea(p));
434 return m_data[m_area.index(p)];
438 Set stuff if available without an emerge.
439 Return false if failed.
440 This is convenient but slower than playing around directly
441 with the m_data table with indices.
443 bool setNodeNoEmerge(v3s16 p, MapNode n)
445 if(m_area.contains(p) == false)
447 m_data[m_area.index(p)] = n;
449 bool setNodeNoEmerge(s32 i, MapNode n)
451 if(m_area.contains(i) == false)
455 /*bool setContentNoEmerge(v3s16 p, u8 c)
457 if(isValidPosition(p) == false)
459 m_data[m_area.index(p)].d = c;
466 virtual void clear();
468 void print(std::ostream &o, VoxelPrintMode mode=VOXELPRINT_MATERIAL);
470 void addArea(VoxelArea area);
473 Copy data and set flags to 0
474 dst_area.getExtent() <= src_area.getExtent()
476 void copyFrom(MapNode *src, VoxelArea src_area,
477 v3s16 from_pos, v3s16 to_pos, v3s16 size);
480 void copyTo(MapNode *dst, VoxelArea dst_area,
481 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
487 void clearFlag(u8 flag);
489 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
490 core::map<v3s16, bool> & light_sources);
491 void unspreadLight(enum LightBank bank,
492 core::map<v3s16, u8> & from_nodes,
493 core::map<v3s16, bool> & light_sources);
495 void spreadLight(enum LightBank bank, v3s16 p);
496 void spreadLight(enum LightBank bank,
497 core::map<v3s16, bool> & from_nodes);
504 Get the contents of the requested area from somewhere.
505 Shall touch only nodes that have VOXELFLAG_NOT_LOADED
506 Shall reset VOXELFLAG_NOT_LOADED
508 If not found from source, add with VOXELFLAG_INEXISTENT
510 virtual void emerge(VoxelArea a, s32 caller_id=-1)
512 //dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
514 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
515 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
516 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
518 s32 i = m_area.index(x,y,z);
519 // Don't touch nodes that have already been loaded
520 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
522 m_flags[i] = VOXELFLAG_INEXISTENT;
531 The area that is stored in m_data.
532 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
533 MaxEdge is 1 higher than maximum allowed position
538 NULL if data size is 0 (extent (0,0,0))
539 Data is stored as [z*h*w + y*h + x]
548 //TODO: Use these or remove them
549 //TODO: Would these make any speed improvement?
550 //bool m_pressure_route_valid;
551 //v3s16 m_pressure_route_surface;
556 //bool m_disable_water_climb;