1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-27 17:28:41 +00:00

Some refactoring and fixes to VoxelArea and VoxelManip

In particular this validates the edges of VoxelArea and fixes
all the nonsense tests uncovered by it.
This commit is contained in:
sfan5 2024-10-07 17:48:19 +02:00
parent 5532248cd7
commit 6d5103900f
11 changed files with 178 additions and 183 deletions

View file

@ -59,7 +59,7 @@ class VoxelArea
{
public:
// Starts as zero sized
VoxelArea() = default;
constexpr VoxelArea() = default;
VoxelArea(const v3s16 &min_edge, const v3s16 &max_edge):
MinEdge(min_edge),
@ -129,12 +129,11 @@ public:
return m_cache_extent;
}
/* Because MaxEdge and MinEdge are included in the voxel area an empty extent
* is not represented by (0, 0, 0), but instead (-1, -1, -1)
*/
/// @note `getVolume() == 0` and `getEmptyExtent()` are not identical.
bool hasEmptyExtent() const
{
return MaxEdge - MinEdge == v3s16(-1, -1, -1);
// FIXME: shouldn't this actually be a component-wise check?
return m_cache_extent == v3s16(0,0,0);
}
s32 getVolume() const
@ -208,83 +207,74 @@ public:
return ret;
}
/*
/**
Returns 0-6 non-overlapping areas that can be added to
a to make up this area.
`a` to make up this area.
a: area inside *this
@tparam C container that has push_back
@param a area inside *this
*/
void diff(const VoxelArea &a, std::list<VoxelArea> &result)
template <typename C>
void diff(const VoxelArea &a, C &result) const
{
/*
This can result in a maximum of 6 areas
*/
// If a is an empty area, return the current area as a whole
if(a.getExtent() == v3s16(0,0,0))
if(a.hasEmptyExtent())
{
VoxelArea b = *this;
if(b.getVolume() != 0)
if (b.getVolume() != 0)
result.push_back(b);
return;
}
assert(contains(a)); // pre-condition
const auto &take = [&result] (v3s16 min, v3s16 max) {
VoxelArea b(min, max);
if (b.getVolume() != 0)
result.push_back(b);
};
// Take back area, XY inclusive
{
v3s16 min(MinEdge.X, MinEdge.Y, a.MaxEdge.Z+1);
v3s16 max(MaxEdge.X, MaxEdge.Y, MaxEdge.Z);
VoxelArea b(min, max);
if(b.getVolume() != 0)
result.push_back(b);
take(min, max);
}
// Take front area, XY inclusive
{
v3s16 min(MinEdge.X, MinEdge.Y, MinEdge.Z);
v3s16 max(MaxEdge.X, MaxEdge.Y, a.MinEdge.Z-1);
VoxelArea b(min, max);
if(b.getVolume() != 0)
result.push_back(b);
take(min, max);
}
// Take top area, X inclusive
{
v3s16 min(MinEdge.X, a.MaxEdge.Y+1, a.MinEdge.Z);
v3s16 max(MaxEdge.X, MaxEdge.Y, a.MaxEdge.Z);
VoxelArea b(min, max);
if(b.getVolume() != 0)
result.push_back(b);
take(min, max);
}
// Take bottom area, X inclusive
{
v3s16 min(MinEdge.X, MinEdge.Y, a.MinEdge.Z);
v3s16 max(MaxEdge.X, a.MinEdge.Y-1, a.MaxEdge.Z);
VoxelArea b(min, max);
if(b.getVolume() != 0)
result.push_back(b);
take(min, max);
}
// Take left area, non-inclusive
{
v3s16 min(MinEdge.X, a.MinEdge.Y, a.MinEdge.Z);
v3s16 max(a.MinEdge.X-1, a.MaxEdge.Y, a.MaxEdge.Z);
VoxelArea b(min, max);
if(b.getVolume() != 0)
result.push_back(b);
take(min, max);
}
// Take right area, non-inclusive
{
v3s16 min(a.MaxEdge.X+1, a.MinEdge.Y, a.MinEdge.Z);
v3s16 max(MaxEdge.X, a.MaxEdge.Y, a.MaxEdge.Z);
VoxelArea b(min, max);
if(b.getVolume() != 0)
result.push_back(b);
take(min, max);
}
}
/*
@ -344,30 +334,34 @@ public:
<< "=" << getVolume();
}
// Edges are inclusive
/// Minimum edge of the area (inclusive)
/// @warning read-only!
v3s16 MinEdge = v3s16(1,1,1);
/// Maximum edge of the area (inclusive)
/// @warning read-only!
v3s16 MaxEdge;
private:
void cacheExtent()
{
m_cache_extent = MaxEdge - MinEdge + v3s16(1,1,1);
// If positions were sorted correctly this must always hold.
// Note that this still permits empty areas (where MinEdge = MaxEdge + 1).
assert(m_cache_extent.X >= 0);
assert(m_cache_extent.Y >= 0);
assert(m_cache_extent.Z >= 0);
}
v3s16 m_cache_extent = v3s16(0,0,0);
};
// unused
#define VOXELFLAG_UNUSED (1 << 0)
// no data about that node
#define VOXELFLAG_NO_DATA (1 << 1)
// Algorithm-dependent
#define VOXELFLAG_CHECKED1 (1 << 2)
// Algorithm-dependent
#define VOXELFLAG_CHECKED2 (1 << 3)
// Algorithm-dependent
#define VOXELFLAG_CHECKED3 (1 << 4)
// Algorithm-dependent
#define VOXELFLAG_CHECKED4 (1 << 5)
enum : u8 {
VOXELFLAG_NO_DATA = 1 << 0, // no data about that node
VOXELFLAG_CHECKED1 = 1 << 1, // Algorithm-dependent
VOXELFLAG_CHECKED2 = 1 << 2, // Algorithm-dependent
VOXELFLAG_CHECKED3 = 1 << 3, // Algorithm-dependent
VOXELFLAG_CHECKED4 = 1 << 4, // Algorithm-dependent
};
enum VoxelPrintMode
{
@ -414,7 +408,7 @@ public:
return m_data[index];
}
MapNode getNodeNoExNoEmerge(const v3s16 &p)
MapNode getNodeNoExNoEmerge(const v3s16 &p) const
{
if (!m_area.contains(p))
return {CONTENT_IGNORE};
@ -430,7 +424,7 @@ public:
return m_data[m_area.index(p)];
}
const MapNode & getNodeRefUnsafeCheckFlags(const v3s16 &p)
const MapNode & getNodeRefUnsafeCheckFlags(const v3s16 &p) const
{
s32 index = m_area.index(p);
@ -483,10 +477,13 @@ public:
virtual void clear();
void print(std::ostream &o, const NodeDefManager *nodemgr,
VoxelPrintMode mode=VOXELPRINT_MATERIAL);
VoxelPrintMode mode=VOXELPRINT_MATERIAL) const;
void addArea(const VoxelArea &area);
void setFlags(const VoxelArea &area, u8 flag);
void clearFlags(const VoxelArea &area, u8 flag);
/*
Copy data and set flags to 0
dst_area.getExtent() <= src_area.getExtent()
@ -496,13 +493,7 @@ public:
// Copy data
void copyTo(MapNode *dst, const VoxelArea& dst_area,
v3s16 dst_pos, v3s16 from_pos, const v3s16 &size);
/*
Algorithms
*/
void clearFlag(u8 flag);
v3s16 dst_pos, v3s16 from_pos, const v3s16 &size) const;
/*
Member variables
@ -510,13 +501,12 @@ public:
/*
The area that is stored in m_data.
addInternalBox should not be used if getExtent() == v3s16(0,0,0)
MaxEdge is 1 higher than maximum allowed position
MaxEdge is 1 higher than maximum allowed position.
*/
VoxelArea m_area;
/*
nullptr if data size is 0 (extent (0,0,0))
nullptr if data size is 0 (empty extent)
Data is stored as [z*h*w + y*h + x]
*/
MapNode *m_data = nullptr;