EinsDreiDreiSieben/mods/cozylights/node_light.lua
2025-05-21 00:34:29 +02:00

192 lines
No EOL
6.3 KiB
Lua

local c_air = minetest.get_content_id("air")
local c_light1 = minetest.get_content_id("cozylights:light1")
local c_lights = { c_light1, c_light1 + 1, c_light1 + 2, c_light1 + 3, c_light1 + 4, c_light1 + 5, c_light1 + 6,
c_light1 + 7, c_light1 + 8, c_light1 + 9, c_light1 + 10, c_light1 + 11, c_light1 + 12, c_light1 + 13 }
local gent_total = 0
local gent_count = 0
local remt_total = 0
local remt_count = 0
local mf = math.floor
local dirfloor = 0.5
--- raycast but normal
local function darknesscast(pos, dir, radius,data,param2data, a)
local px, py, pz, dx, dy, dz = pos.x, pos.y, pos.z, dir.x, dir.y, dir.z
local c_light1 = c_lights[1]
local c_light14 = c_lights[14]
for i = 1, radius do
local x = mf(dx*i+dirfloor) + px
local y = mf(dy*i+dirfloor) + py
local z = mf(dz*i+dirfloor) + pz
local idx = a:index(x,y,z)
local cid = data[idx]
if cid and (cid == c_air or (cid >= c_light1 and cid <= c_light14+14)) then
data[idx] = c_air
param2data[idx] = 0
else
break
end
end
end
function cozylights:draw_node_light(pos,cozy_item,vm,a,data,param2data,fix_edges)
local t = os.clock()
local update_needed = 0
local radius, dim_levels = cozylights:calc_dims(cozy_item)
--print("cozy_item:"..cozylights:dump(cozy_item))
--print("dim_levels: "..cozylights:dump(dim_levels))
--print("spreading light over a sphere with radius of "..radius)
if vm == nil then
_,_,vm,data,param2data,a = cozylights:getVoxelManipData(pos,radius)
update_needed = 1
end
local sphere_surface = cozylights:get_sphere_surface(radius)
local ylvl = 1
local cid = data[a:index(pos.x,pos.y-1,pos.z)]
local cida = data[a:index(pos.x,pos.y+1,pos.z)]
if cid and cida then
if (cid == c_air or (cid >= c_lights[1] and cid <= c_lights[14]))
and cida ~= c_air and (cida < c_lights[1] or cida > c_lights[14])
then
ylvl = -1
end
else
return
end
pos.y = pos.y + ylvl
fix_edges = fix_edges == nil and cozylights.always_fix_edges or fix_edges
if fix_edges == true then
local visited_pos = {}
for i,pos2 in ipairs(sphere_surface) do
local end_pos = {x=pos.x+pos2.x,y=pos.y+pos2.y,z=pos.z+pos2.z}
cozylights:lightcast_fix_edges(pos, vector.direction(pos, end_pos),radius,data,param2data,a,dim_levels,visited_pos)
end
else
for i,pos2 in ipairs(sphere_surface) do
local end_pos = {x=pos.x+pos2.x,y=pos.y+pos2.y,z=pos.z+pos2.z}
cozylights.dir = vector.direction(pos, end_pos)
cozylights:lightcast(pos, vector.direction(pos, end_pos),radius,data,param2data,a,dim_levels)
end
end
if update_needed == 1 then
cozylights:setVoxelManipData(vm,data,param2data,true)
end
gent_total = gent_total + mf((os.clock() - t) * 1000)
gent_count = gent_count + 1
--print("Av illum time " .. mf(gent_total/gent_count) .. " ms. Sample of: "..gent_count)
end
-- handle_async?
function cozylights:rebuild_light()
local single_light_queue = cozylights.single_light_queue
if #single_light_queue == 0 then
return
end
--print("#single_light_queue is: "..#single_light_queue)
cozylights:draw_node_light(single_light_queue[1].pos, single_light_queue[1].cozy_item)
table.remove(single_light_queue, 1)
end
function cozylights:destroy_light(pos, cozy_item)
local t = os.clock()
local radius = cozylights:calc_dims(cozy_item)
local _,_,vm,data,param2data,a = cozylights:getVoxelManipData(pos, radius)
local sphere_surface = cozylights:get_sphere_surface(radius)
local ylvl = 1
local cid = data[a:index(pos.x,pos.y-1,pos.z)]
local cida = data[a:index(pos.x,pos.y+1,pos.z)]
if cid and cida then
if (cid == c_air or (cid >= c_lights[1] and cid <= c_lights[14]))
and cida ~= c_air and (cida < c_lights[1] or cida > c_lights[14])
then
ylvl = -1
end
else
return
end
pos.y = pos.y + ylvl
for i,pos2 in ipairs(sphere_surface) do
local end_pos = {x=pos.x+pos2.x,y=pos.y+pos2.y,z=pos.z+pos2.z}
darknesscast(pos, vector.direction(pos, end_pos),radius,data,param2data, a)
end
cozylights:setVoxelManipData(vm,data,param2data)
local rebuild_range = 78
local rebuild_minp = vector.subtract(pos, rebuild_range)
local rebuild_maxp = vector.add(pos, rebuild_range)
local posrebuilds = minetest.find_nodes_in_area(
rebuild_minp,
rebuild_maxp,
cozylights.source_nodes
)
local pos_hash = pos.x + (pos.y-ylvl)*100 + pos.z*10000
local sources = {}
if #posrebuilds > 0 then
local single_light_queue = cozylights.single_light_queue
for i=1,#posrebuilds do
local posrebuild = posrebuilds[i]
local posrebuild_hash = posrebuild.x + posrebuild.y*100 + posrebuild.z*10000
if posrebuild_hash ~= pos_hash then
local node = minetest.get_node(posrebuild)
local rebuild_radius, _ = cozylights:calc_dims(cozylights.cozy_items[node.name])
local max_distance = rebuild_radius + radius
if max_distance > vector.distance(pos,posrebuild) then
if vector.in_area(vector.subtract(posrebuild,rebuild_radius), rebuild_minp, rebuild_maxp)
and vector.in_area(vector.add(posrebuild,rebuild_radius), rebuild_minp, rebuild_maxp)
then
sources[#sources+1] = {
pos=posrebuild,
cozy_item=cozylights.cozy_items[node.name]
}
else
cozylights.single_light_queue[#single_light_queue+1] = {
pos=posrebuilds[i],
cozy_item=cozylights.cozy_items[node.name]
}
end
end
end
end
end
if #sources > 0 then
cozylights.area_queue[#cozylights.area_queue+1]={
minp=rebuild_minp,
maxp=rebuild_maxp,
sources=sources
}
end
remt_total = remt_total + mf((os.clock() - t) * 1000)
remt_count = remt_count + 1
print("Av light removal time " .. mf(remt_total/remt_count) .. " ms. Sample of: "..remt_count)
end
--[[
function cozylights:rebuild_light(pos, cozy_item,vm,a,data,param2data)
local radius, dim_levels = cozylights:calc_dims(cozy_item)
print("rebuilding light for position "..cozylights:dump(pos))
local sphere_surface = cozylights:get_sphere_surface(radius)
local ylvl = 1
local cid = data[a:index(pos.x,pos.y-1,pos.z)]
local cida = data[a:index(pos.x,pos.y+1,pos.z)]
if cid and cida then
if (cid == c_air or (cid >= c_lights[1] and cid <= c_lights[14]))
and cida ~= c_air and (cida < c_lights[1] or cida > c_lights[14])
then
ylvl = -1
end
else
return
end
pos.y = pos.y + ylvl
for _,pos2 in ipairs(sphere_surface) do
local end_pos = {x=pos.x+pos2.x,y=pos.y+pos2.y,z=pos.z+pos2.z}
if a:containsp(end_pos) then
cozylights:lightcast(pos, vector.direction(pos, end_pos),radius,data,param2data,a,dim_levels)
end
end
end]]