]> git.lizzy.rs Git - minetest.git/blob - builtin/game/voxelarea.lua
a9195213bdbd3ea74a8b7e385027d2a3de7831e8
[minetest.git] / builtin / game / voxelarea.lua
1 local math_floor = math.floor
2 local vector_new = vector.new
3
4 VoxelArea = {
5         MinEdge = vector_new(1, 1, 1),
6         MaxEdge = vector_new(0, 0, 0),
7         ystride = 0,
8         zstride = 0,
9 }
10
11 local class_metatable = {}
12 setmetatable(VoxelArea, class_metatable)
13
14 local function new(self, o)
15         o = o or {}
16         setmetatable(o, self)
17         self.__index = self
18
19         local e = o:getExtent()
20         o.ystride = e.x
21         o.zstride = e.x * e.y
22
23         return o
24 end
25
26 function class_metatable:__call(MinEdge, MaxEdge)
27         return new(self, {MinEdge = MinEdge, MaxEdge = MaxEdge})
28 end
29
30 VoxelArea.new = new
31
32 function VoxelArea:getExtent()
33         local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
34         return vector_new(
35                 MaxEdge.x - MinEdge.x + 1,
36                 MaxEdge.y - MinEdge.y + 1,
37                 MaxEdge.z - MinEdge.z + 1
38         )
39 end
40
41 function VoxelArea:getVolume()
42         local e = self:getExtent()
43         return e.x * e.y * e.z
44 end
45
46 function VoxelArea:index(x, y, z)
47         local MinEdge = self.MinEdge
48         local i = (z - MinEdge.z) * self.zstride +
49                           (y - MinEdge.y) * self.ystride +
50                           (x - MinEdge.x) + 1
51         return math_floor(i)
52 end
53
54 function VoxelArea:indexp(p)
55         local MinEdge = self.MinEdge
56         local i = (p.z - MinEdge.z) * self.zstride +
57                           (p.y - MinEdge.y) * self.ystride +
58                           (p.x - MinEdge.x) + 1
59         return math_floor(i)
60 end
61
62 function VoxelArea:position(i)
63         local MinEdge = self.MinEdge
64
65         i = i - 1
66
67         local z = math_floor(i / self.zstride) + MinEdge.z
68         i = i % self.zstride
69
70         local y = math_floor(i / self.ystride) + MinEdge.y
71         i = i % self.ystride
72
73         local x = math_floor(i) + MinEdge.x
74
75         return vector_new(x, y, z)
76 end
77
78 function VoxelArea:contains(x, y, z)
79         local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
80         return (x >= MinEdge.x) and (x <= MaxEdge.x) and
81                    (y >= MinEdge.y) and (y <= MaxEdge.y) and
82                    (z >= MinEdge.z) and (z <= MaxEdge.z)
83 end
84
85 function VoxelArea:containsp(p)
86         local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
87         return (p.x >= MinEdge.x) and (p.x <= MaxEdge.x) and
88                    (p.y >= MinEdge.y) and (p.y <= MaxEdge.y) and
89                    (p.z >= MinEdge.z) and (p.z <= MaxEdge.z)
90 end
91
92 function VoxelArea:containsi(i)
93         return (i >= 1) and (i <= self:getVolume())
94 end
95
96 function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz)
97         local i = self:index(minx, miny, minz) - 1
98         local xrange = maxx - minx + 1
99         local nextaction = i + 1 + xrange
100
101         local y = 0
102         local yrange = maxy - miny + 1
103         local yreqstride = self.ystride - xrange
104
105         local z = 0
106         local zrange = maxz - minz + 1
107         local multistride = self.zstride - ((yrange - 1) * self.ystride + xrange)
108
109         return function()
110                 -- continue i until it needs to jump
111                 i = i + 1
112                 if i ~= nextaction then
113                         return i
114                 end
115
116                 -- continue y until maxy is exceeded
117                 y = y + 1
118                 if y ~= yrange then
119                         -- set i to index(minx, miny + y, minz + z) - 1
120                         i = i + yreqstride
121                         nextaction = i + xrange
122                         return i
123                 end
124
125                 -- continue z until maxz is exceeded
126                 z = z + 1
127                 if z == zrange then
128                         -- cuboid finished, return nil
129                         return
130                 end
131
132                 -- set i to index(minx, miny, minz + z) - 1
133                 i = i + multistride
134
135                 y = 0
136                 nextaction = i + xrange
137                 return i
138         end
139 end
140
141 function VoxelArea:iterp(minp, maxp)
142         return self:iter(minp.x, minp.y, minp.z, maxp.x, maxp.y, maxp.z)
143 end