Files

275 lines
8.5 KiB
Lua

local circles = {}
-- Calculate the values for the segments of the circles
do
local sqrt2 = math.sqrt(2) * 0.5
local rad90 = math.rad(90)
local pos = vector.new(sqrt2, 0, sqrt2)
local vel = vector.new((1 - sqrt2) * 2, 0, -sqrt2)
local acc = vector.new((1 - sqrt2) * -2, 0, 0)
local axes = {
x = vector.new(1, 0, 0),
y = vector.new(0, 1, 0),
z = vector.new(0, 0, 1),
}
for _,axis in ipairs({"y", "x", "z"}) do -- This order is important
circles[axis] = {}
if axis == "x" then
pos = vector.rotate_around_axis(pos, axes.z, rad90)
vel = vector.rotate_around_axis(vel, axes.z, rad90)
acc = vector.rotate_around_axis(acc, axes.z, rad90)
elseif axis == "z" then
pos = vector.rotate_around_axis(pos, axes.y, rad90)
vel = vector.rotate_around_axis(vel, axes.y, rad90)
acc = vector.rotate_around_axis(acc, axes.y, rad90)
end
for i=1, 4 do
circles[axis][i] = {
pos = vector.rotate_around_axis(pos, axes[axis], rad90 * i),
vel = vector.rotate_around_axis(vel, axes[axis], rad90 * i),
acc = vector.rotate_around_axis(acc, axes[axis], rad90 * i),
}
end
end
end
local function get_valid_options(options)
if type(options) ~= "table" then
options = {}
end
local color = options.color or vizlib.default_color
for _,c in ipairs(vizlib.colors) do
if c.name == color then
color = c.hex
end
end
local time = options.infinite and 0 or 10
local density = options.infinite and 1 or 10
local name
local t = type(options.player)
if t == "string" then
name = options.player
elseif t == "userdata" or t == "table" then
name = options.player:get_player_name()
end
return color, name, time, density
end
local function make_shape(name, time, ids)
local shape = {name = name}
if time > 0 then
shape.expiry = os.time() + time
end
if type(ids) ~= "table" then
shape.ids = {ids}
else
shape.ids = ids
end
return shape
end
local function make_arc(arc, pos, radius, color, name, time, density)
pos = vector.add(pos, vector.multiply(arc.pos, radius))
local vel = vector.multiply(arc.vel, radius)
local acc = vector.multiply(arc.acc, radius)
return minetest.add_particlespawner({
playername = name,
time = time,
amount = math.ceil(radius * density * 6.0),
minpos = pos,
maxpos = pos,
minvel = vel,
maxvel = vel,
minacc = acc,
maxacc = acc,
minexptime = 2,
maxexptime = 2,
texture = "vizlib_particle.png^[multiply:"..color,
glow = 14,
})
end
local function make_line(pos1, pos2, color, name, time, density)
local distance = vector.distance(pos1, pos2)
local dir = vector.direction(pos1, pos2)
local vel = vector.multiply(dir, math.min(distance, 10.0))
local expt = math.max(distance / 10.0, 1.0)
return minetest.add_particlespawner({
playername = name,
time = time,
amount = math.ceil(math.min(distance, 10.0) * density * 3.0),
minpos = pos1,
maxpos = pos1,
minvel = vel,
maxvel = vel,
minexptime = expt,
maxexptime = expt,
texture = "vizlib_particle.png^[multiply:"..color,
glow = 14,
})
end
local function make_point(pos, color, name, time, density)
return minetest.add_particlespawner({
playername = name,
time = time,
amount = density * 2,
minpos = pos,
maxpos = pos,
minexptime = 2.0,
maxexptime = 2.0,
texture = "vizlib_particle.png^[multiply:"..color,
glow = 14,
size = 1.5,
})
end
--------------------------------------------------
-- API Functions. See API.md for details.
--------------------------------------------------
function vizlib.select_color()
return vizlib.colors[math.random(24)].hex
end
function vizlib.random_color()
local r = math.random(0, 255)
local g = math.random(0, 255)
local b = math.random(0, 255)
return string.format("#%02x%02x%02x", r, g, b)
end
function vizlib.draw_point(pos, options)
local color, name, time, density = get_valid_options(options)
local ids = make_point(pos, color, name, time, density)
return make_shape(name, time, ids)
end
function vizlib.draw_circle(pos, radius, axis, options)
local color, name, time, density = get_valid_options(options)
local ids = {}
for _,arc in pairs(circles[axis]) do
table.insert(ids, make_arc(arc, pos, radius, color, name, time, density))
end
return make_shape(name, time, ids)
end
function vizlib.draw_sphere(pos, radius, options)
local color, name, time, density = get_valid_options(options)
local ids = {}
for _,circle in pairs(circles) do
for _,arc in pairs(circle) do
table.insert(ids, make_arc(arc, pos, radius, color, name, time, density))
end
end
return make_shape(name, time, ids)
end
function vizlib.draw_line(pos1, pos2, options)
local color, name, time, density = get_valid_options(options)
local ids = make_line(pos1, pos2, color, name, time, density)
return make_shape(name, time, ids)
end
function vizlib.draw_square(pos, radius, axis, options)
local color, name, time, density = get_valid_options(options)
local p1, p2, p3, p4
if axis == "x" then
p1 = vector.add(pos, vector.new(0, -radius, -radius))
p2 = vector.add(pos, vector.new(0, radius, -radius))
p3 = vector.add(pos, vector.new(0, radius, radius))
p4 = vector.add(pos, vector.new(0, -radius, radius))
elseif axis == "y" then
p1 = vector.add(pos, vector.new(-radius, 0, -radius))
p2 = vector.add(pos, vector.new( radius, 0, -radius))
p3 = vector.add(pos, vector.new( radius, 0, radius))
p4 = vector.add(pos, vector.new(-radius, 0, radius))
elseif axis == "z" then
p1 = vector.add(pos, vector.new(-radius, -radius, 0))
p2 = vector.add(pos, vector.new( radius, -radius, 0))
p3 = vector.add(pos, vector.new( radius, radius, 0))
p4 = vector.add(pos, vector.new(-radius, radius, 0))
end
local ids = {
make_line(p1, p2, color, name, time, density),
make_line(p2, p3, color, name, time, density),
make_line(p3, p4, color, name, time, density),
make_line(p4, p1, color, name, time, density),
}
return make_shape(name, time, ids)
end
function vizlib.draw_cube(pos, radius, options)
local color, name, time, density = get_valid_options(options)
local p1 = vector.add(pos, vector.new(-radius, radius, -radius))
local p2 = vector.add(pos, vector.new( radius, radius, -radius))
local p3 = vector.add(pos, vector.new( radius, radius, radius))
local p4 = vector.add(pos, vector.new(-radius, radius, radius))
local p5 = vector.add(pos, vector.new(-radius, -radius, -radius))
local p6 = vector.add(pos, vector.new( radius, -radius, -radius))
local p7 = vector.add(pos, vector.new( radius, -radius, radius))
local p8 = vector.add(pos, vector.new(-radius, -radius, radius))
local ids = {
-- Top
make_line(p1, p2, color, name, time, density),
make_line(p2, p3, color, name, time, density),
make_line(p3, p4, color, name, time, density),
make_line(p4, p1, color, name, time, density),
-- Bottom
make_line(p5, p6, color, name, time, density),
make_line(p6, p7, color, name, time, density),
make_line(p7, p8, color, name, time, density),
make_line(p8, p5, color, name, time, density),
-- Sides
make_line(p1, p5, color, name, time, density),
make_line(p2, p6, color, name, time, density),
make_line(p3, p7, color, name, time, density),
make_line(p4, p8, color, name, time, density),
}
return make_shape(name, time, ids)
end
function vizlib.draw_area(pos1, pos2, options)
local color, name, time, density = get_valid_options(options)
local minp, maxp = {}, {}
for _,c in pairs({"x", "y", "z"}) do
minp[c] = math.min(pos1[c], pos2[c])
maxp[c] = math.max(pos1[c], pos2[c])
end
local p1 = vector.new(minp.x, maxp.y, minp.z)
local p2 = vector.new(maxp.x, maxp.y, minp.z)
local p3 = vector.new(maxp.x, maxp.y, maxp.z)
local p4 = vector.new(minp.x, maxp.y, maxp.z)
local p5 = vector.new(minp.x, minp.y, minp.z)
local p6 = vector.new(maxp.x, minp.y, minp.z)
local p7 = vector.new(maxp.x, minp.y, maxp.z)
local p8 = vector.new(minp.x, minp.y, maxp.z)
local ids = {
-- Top
make_line(p1, p2, color, name, time, density),
make_line(p2, p3, color, name, time, density),
make_line(p3, p4, color, name, time, density),
make_line(p4, p1, color, name, time, density),
-- Bottom
make_line(p5, p6, color, name, time, density),
make_line(p6, p7, color, name, time, density),
make_line(p7, p8, color, name, time, density),
make_line(p8, p5, color, name, time, density),
-- Sides
make_line(p1, p5, color, name, time, density),
make_line(p2, p6, color, name, time, density),
make_line(p3, p7, color, name, time, density),
make_line(p4, p8, color, name, time, density),
}
return make_shape(name, time, ids)
end
function vizlib.erase_shape(shape)
if type(shape) ~= "table" or not shape.ids then
return
end
for _,id in pairs(shape.ids) do
minetest.delete_particlespawner(id)
end
end