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 void setNode(v3s16 p, MapNode &n)
380 m_data[m_area.index(p)] = n;
381 m_flags[m_area.index(p)] &= ~VOXELFLAG_INEXISTENT;
382 m_flags[m_area.index(p)] &= ~VOXELFLAG_NOT_LOADED;
384 void setNodeNoRef(v3s16 p, MapNode n)
389 /*void setExists(VoxelArea a)
392 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
393 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
394 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
396 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_INEXISTENT;
400 /*MapNode & operator[](v3s16 p)
402 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
403 if(isValidPosition(p) == false)
404 emerge(VoxelArea(p));
406 return m_data[m_area.index(p)];
410 Set stuff if available without an emerge.
411 Return false if failed.
412 This is convenient but slower than playing around directly
413 with the m_data table with indices.
415 bool setNodeNoEmerge(v3s16 p, MapNode n)
417 if(m_area.contains(p) == false)
419 m_data[m_area.index(p)] = n;
421 bool setNodeNoEmerge(s32 i, MapNode n)
423 if(m_area.contains(i) == false)
427 /*bool setContentNoEmerge(v3s16 p, u8 c)
429 if(isValidPosition(p) == false)
431 m_data[m_area.index(p)].d = c;
438 virtual void clear();
440 void print(std::ostream &o, VoxelPrintMode mode=VOXELPRINT_MATERIAL);
442 void addArea(VoxelArea area);
445 Copy data and set flags to 0
446 dst_area.getExtent() <= src_area.getExtent()
448 void copyFrom(MapNode *src, VoxelArea src_area,
449 v3s16 from_pos, v3s16 to_pos, v3s16 size);
452 void copyTo(MapNode *dst, VoxelArea dst_area,
453 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
459 void clearFlag(u8 flag);
461 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
462 core::map<v3s16, bool> & light_sources);
463 void unspreadLight(enum LightBank bank,
464 core::map<v3s16, u8> & from_nodes,
465 core::map<v3s16, bool> & light_sources);
467 void spreadLight(enum LightBank bank, v3s16 p);
468 void spreadLight(enum LightBank bank,
469 core::map<v3s16, bool> & from_nodes);
476 Get the contents of the requested area from somewhere.
477 Shall touch only nodes that have VOXELFLAG_NOT_LOADED
478 Shall reset VOXELFLAG_NOT_LOADED
480 If not found from source, add with VOXELFLAG_INEXISTENT
482 virtual void emerge(VoxelArea a, s32 caller_id=-1)
484 //dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
486 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
487 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
488 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
490 s32 i = m_area.index(x,y,z);
491 // Don't touch nodes that have already been loaded
492 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
494 m_flags[i] = VOXELFLAG_INEXISTENT;
503 The area that is stored in m_data.
504 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
505 MaxEdge is 1 higher than maximum allowed position
510 NULL if data size is 0 (extent (0,0,0))
511 Data is stored as [z*h*w + y*h + x]
520 //TODO: Use these or remove them
521 //TODO: Would these make any speed improvement?
522 //bool m_pressure_route_valid;
523 //v3s16 m_pressure_route_surface;
528 bool m_disable_water_climb;