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"
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,
338 class VoxelManipulator /*: public NodeContainer*/
342 virtual ~VoxelManipulator();
345 Virtuals from NodeContainer
347 /*virtual u16 nodeContainerId() const
349 return NODECONTAINER_ID_VOXELMANIPULATOR;
351 bool isValidPosition(v3s16 p)
354 return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT);
358 These are a bit slow and shouldn't be used internally.
359 Use m_data[m_area.index(p)] instead.
361 MapNode getNode(v3s16 p)
365 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
367 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
368 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
369 <<", index="<<m_area.index(p)
370 <<", flags="<<(int)m_flags[m_area.index(p)]
371 <<" is inexistent"<<std::endl;*/
372 throw InvalidPositionException
373 ("VoxelManipulator: getNode: inexistent");
376 return m_data[m_area.index(p)];
378 MapNode getNodeNoEx(v3s16 p)
382 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
384 return MapNode(CONTENT_IGNORE);
387 return m_data[m_area.index(p)];
389 MapNode getNodeNoExNoEmerge(v3s16 p)
391 if(m_area.contains(p) == false)
392 return MapNode(CONTENT_IGNORE);
393 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
394 return MapNode(CONTENT_IGNORE);
395 return m_data[m_area.index(p)];
397 MapNode & getNodeRef(v3s16 p)
401 if(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT)
403 /*dstream<<"EXCEPT: VoxelManipulator::getNode(): "
404 <<"p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"
405 <<", index="<<m_area.index(p)
406 <<", flags="<<(int)m_flags[m_area.index(p)]
407 <<" is inexistent"<<std::endl;*/
408 throw InvalidPositionException
409 ("VoxelManipulator: getNode: inexistent");
412 return m_data[m_area.index(p)];
414 void setNode(v3s16 p, MapNode &n)
418 m_data[m_area.index(p)] = n;
419 m_flags[m_area.index(p)] &= ~VOXELFLAG_INEXISTENT;
420 m_flags[m_area.index(p)] &= ~VOXELFLAG_NOT_LOADED;
422 void setNodeNoRef(v3s16 p, MapNode n)
427 /*void setExists(VoxelArea a)
430 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
431 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
432 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
434 m_flags[m_area.index(x,y,z)] &= ~VOXELFLAG_INEXISTENT;
438 /*MapNode & operator[](v3s16 p)
440 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
441 if(isValidPosition(p) == false)
442 emerge(VoxelArea(p));
444 return m_data[m_area.index(p)];
448 Set stuff if available without an emerge.
449 Return false if failed.
450 This is convenient but slower than playing around directly
451 with the m_data table with indices.
453 bool setNodeNoEmerge(v3s16 p, MapNode n)
455 if(m_area.contains(p) == false)
457 m_data[m_area.index(p)] = n;
460 bool setNodeNoEmerge(s32 i, MapNode n)
462 if(m_area.contains(i) == false)
467 /*bool setContentNoEmerge(v3s16 p, u8 c)
469 if(isValidPosition(p) == false)
471 m_data[m_area.index(p)].d = c;
478 virtual void clear();
480 void print(std::ostream &o, INodeDefManager *nodemgr,
481 VoxelPrintMode mode=VOXELPRINT_MATERIAL);
483 void addArea(VoxelArea area);
486 Copy data and set flags to 0
487 dst_area.getExtent() <= src_area.getExtent()
489 void copyFrom(MapNode *src, VoxelArea src_area,
490 v3s16 from_pos, v3s16 to_pos, v3s16 size);
493 void copyTo(MapNode *dst, VoxelArea dst_area,
494 v3s16 dst_pos, v3s16 from_pos, v3s16 size);
500 void clearFlag(u8 flag);
502 void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
503 core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
504 void unspreadLight(enum LightBank bank,
505 core::map<v3s16, u8> & from_nodes,
506 core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr);
508 void spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr);
509 void spreadLight(enum LightBank bank,
510 core::map<v3s16, bool> & from_nodes, INodeDefManager *nodemgr);
517 Get the contents of the requested area from somewhere.
518 Shall touch only nodes that have VOXELFLAG_NOT_LOADED
519 Shall reset VOXELFLAG_NOT_LOADED
521 If not found from source, add with VOXELFLAG_INEXISTENT
523 virtual void emerge(VoxelArea a, s32 caller_id=-1)
525 //dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
527 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
528 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
529 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
531 s32 i = m_area.index(x,y,z);
532 // Don't touch nodes that have already been loaded
533 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
535 m_flags[i] = VOXELFLAG_INEXISTENT;
544 The area that is stored in m_data.
545 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
546 MaxEdge is 1 higher than maximum allowed position
551 NULL if data size is 0 (extent (0,0,0))
552 Data is stored as [z*h*w + y*h + x]
561 //TODO: Use these or remove them
562 //TODO: Would these make any speed improvement?
563 //bool m_pressure_route_valid;
564 //v3s16 m_pressure_route_surface;
569 //bool m_disable_water_climb;