meshport-cd2025/nodebox.lua
David Leal 4d82af8f9d
Add GitHub workflow and LuaCheck (#5)
* Add GitHub workflow and LuaCheck

* Fix warning reported by LuaCheck

* Add build status and license badge

* Remove unused variable (fix warning)

* Revert "Remove unused variable (fix warning)"
2020-09-05 18:39:34 -07:00

195 lines
6.1 KiB
Lua

meshport.side_box_names = {
"top", -- Y+
"bottom", -- Y-
"right", -- X+
"left", -- X-
"back", -- Z+
"front", -- Z-
}
function meshport.sort_box(box)
return {
math.min(box[1], box[4]),
math.min(box[2], box[5]),
math.min(box[3], box[6]),
math.max(box[1], box[4]),
math.max(box[2], box[5]),
math.max(box[3], box[6]),
}
end
meshport.Boxes = {}
function meshport.Boxes:new(boxes)
local o = {}
if type(boxes) ~= "table" or type(boxes[1]) == "number" then
o.boxes = {boxes}
else
o.boxes = boxes
end
setmetatable(o, self)
self.__index = self
return o
end
function meshport.Boxes:insert_all(boxes)
for _, box in ipairs(boxes.boxes) do
table.insert(self.boxes, table.copy(box))
end
end
function meshport.Boxes:transform(func)
local a, b
for i, box in ipairs(self.boxes) do
a = func(vector.new(box[1], box[2], box[3]))
b = func(vector.new(box[4], box[5], box[6]))
self.boxes[i] = {a.x, a.y, a.z, b.x, b.y, b.z}
end
end
function meshport.Boxes:rotate_by_facedir(facedir)
local a, b
for i, box in ipairs(self.boxes) do
a = meshport.rotate_vector_by_facedir(vector.new(box[1], box[2], box[3]), facedir)
b = meshport.rotate_vector_by_facedir(vector.new(box[4], box[5], box[6]), facedir)
self.boxes[i] = {a.x, a.y, a.z, b.x, b.y, b.z}
end
end
function meshport.Boxes:get_leveled(level)
local newBoxes = meshport.Boxes:new(table.copy(self.boxes))
for i, box in ipairs(newBoxes.boxes) do
box = meshport.sort_box(box)
box[5] = level / 64 - 0.5
newBoxes.boxes[i] = box
end
return newBoxes
end
function meshport.Boxes:to_faces(nodeTiles, pos, facedir)
local faces = meshport.Faces:new()
for _, b in ipairs(self.boxes) do
b = meshport.sort_box(b)
local sideFaces = {
{{x = b[4], y = b[5], z = b[3]}, {x = b[4], y = b[5], z = b[6]}, {x = b[1], y = b[5], z = b[6]}, {x = b[1], y = b[5], z = b[3]}}, -- Y+
{{x = b[4], y = b[2], z = b[6]}, {x = b[4], y = b[2], z = b[3]}, {x = b[1], y = b[2], z = b[3]}, {x = b[1], y = b[2], z = b[6]}}, -- Y-
{{x = b[4], y = b[2], z = b[6]}, {x = b[4], y = b[5], z = b[6]}, {x = b[4], y = b[5], z = b[3]}, {x = b[4], y = b[2], z = b[3]}}, -- X+
{{x = b[1], y = b[2], z = b[3]}, {x = b[1], y = b[5], z = b[3]}, {x = b[1], y = b[5], z = b[6]}, {x = b[1], y = b[2], z = b[6]}}, -- X-
{{x = b[1], y = b[2], z = b[6]}, {x = b[1], y = b[5], z = b[6]}, {x = b[4], y = b[5], z = b[6]}, {x = b[4], y = b[2], z = b[6]}}, -- Z+
{{x = b[4], y = b[2], z = b[3]}, {x = b[4], y = b[5], z = b[3]}, {x = b[1], y = b[5], z = b[3]}, {x = b[1], y = b[2], z = b[3]}}, -- Z-
}
local sideTexCoords = {
{{x = b[4], y = b[3]}, {x = b[4], y = b[6]}, {x = b[1], y = b[6]}, {x = b[1], y = b[3]}}, -- Y+
{{x = b[4], y =-b[6]}, {x = b[4], y =-b[3]}, {x = b[1], y =-b[3]}, {x = b[1], y =-b[6]}}, -- Y-
{{x = b[6], y = b[2]}, {x = b[6], y = b[5]}, {x = b[3], y = b[5]}, {x = b[3], y = b[2]}}, -- X+
{{x =-b[3], y = b[2]}, {x =-b[3], y = b[5]}, {x =-b[6], y = b[5]}, {x =-b[6], y = b[2]}}, -- X-
{{x =-b[1], y = b[2]}, {x =-b[1], y = b[5]}, {x =-b[4], y = b[5]}, {x =-b[4], y = b[2]}}, -- Z+
{{x = b[4], y = b[2]}, {x = b[4], y = b[5]}, {x = b[1], y = b[5]}, {x = b[1], y = b[2]}}, -- Z-
}
local vertNorm
for i = 1, 6 do
-- Fix offset texture coordinates.
for v = 1, 4 do
sideTexCoords[i][v] = {x = sideTexCoords[i][v].x + 0.5, y = sideTexCoords[i][v].y + 0.5}
end
vertNorm = meshport.neighbor_dirs[i]
faces:insert_face(meshport.prepare_cuboid_face({
verts = sideFaces[i],
tex_coords = sideTexCoords[i],
vert_norms = {vertNorm, vertNorm, vertNorm, vertNorm},
}, nodeTiles, pos, facedir, i))
end
end
return faces
end
function meshport.prepare_nodebox(nodebox)
local prepNodebox = {}
prepNodebox.type = nodebox.type
if nodebox.type == "regular" then
prepNodebox.fixed = meshport.Boxes:new({-0.5, -0.5, -0.5, 0.5, 0.5, 0.5})
elseif nodebox.type == "fixed" or nodebox.type == "leveled" then
prepNodebox.fixed = meshport.Boxes:new(nodebox.fixed)
elseif nodebox.type == "connected" then
prepNodebox.fixed = meshport.Boxes:new(nodebox.fixed)
prepNodebox.connected = {}
prepNodebox.disconnected = {}
for i, name in ipairs(meshport.side_box_names) do
prepNodebox.connected[i] = meshport.Boxes:new(nodebox["connect_" .. name])
prepNodebox.disconnected[i] = meshport.Boxes:new(nodebox["disconnected_" .. name])
end
prepNodebox.disconnected_all = meshport.Boxes:new(nodebox.disconnected)
prepNodebox.disconnected_sides = meshport.Boxes:new(nodebox.disconnected_sides)
elseif nodebox.type == "wallmounted" then
prepNodebox.wall_bottom = meshport.Boxes:new(nodebox.wall_bottom)
prepNodebox.wall_top = meshport.Boxes:new(nodebox.wall_top)
prepNodebox.wall_side = meshport.Boxes:new(nodebox.wall_side)
-- Rotate the boxes so they are in the correct orientation after rotation by facedir.
prepNodebox.wall_top:transform(function(v) return {x = -v.x, y = -v.y, z = v.z} end)
prepNodebox.wall_side:transform(function(v) return {x = -v.z, y = v.x, z = v.y} end)
end
return prepNodebox
end
function meshport.collect_boxes(prepNodebox, nodeDef, facedir, param2, neighbors)
local boxes = meshport.Boxes:new()
if prepNodebox.fixed then
if prepNodebox.type == "leveled" then
boxes:insert_all(prepNodebox.fixed:get_leveled(
nodeDef.paramtype2 == "leveled" and param2 or nodeDef.leveled or 0))
else
boxes:insert_all(prepNodebox.fixed)
end
end
if prepNodebox.type == "connected" then
local neighborName
for i = 1, 6 do
neighborName = minetest.get_name_from_content_id(neighbors[i])
if meshport.node_connects_to(neighborName, nodeDef.connects_to) then
boxes:insert_all(prepNodebox.connected[i])
else
boxes:insert_all(prepNodebox.disconnected[i])
end
end
elseif prepNodebox.type == "wallmounted" then
if nodeDef.paramtype2 == "wallmounted" or nodeDef.paramtype2 == "colorwallmounted" then
if facedir == 20 then
boxes:insert_all(prepNodebox.wall_top)
elseif facedir == 0 then
boxes:insert_all(prepNodebox.wall_bottom)
else
boxes:insert_all(prepNodebox.wall_side)
end
else
boxes:insert_all(prepNodebox.wall_top)
end
end
return boxes
end