Completely different approach to the underground lighting problem

as per paramat's recommendation a temporary "shadow caster" layer
is written above the chunk when underground relative to the current
layer. This works perfectly and lighting works properly while at
the same time it is calculated by the engine. A major change in the
API was however necessary to limit memory usage. The VM, are and
VM data are now initialized in the multi_map core, and passed on
to the generators as otherwise multiple data arrays were created
(one for the shadow caster, one of the generator, one to remove
the shadow caster again) and multiple calls to set_data and
write_to_map... This is also much better in case generators
are chained (i.e. multiple generators being called within a
single mapgen on_generated call)
This commit is contained in:
evrooije 2018-07-22 14:24:43 +02:00
parent 39bccf6bef
commit b0093461a5
2 changed files with 60 additions and 27 deletions

View File

@ -143,6 +143,17 @@ function multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, content_
end
end
-- Helper to create a 1 node high plane on the specified y
function multi_map.generate_singlenode_plane(minp, maxp, area, vm_data, y, content_id)
for z = minp.z, maxp.z do
local vi = area:index(minp.x, y, z)
for x = minp.x, maxp.x do
vm_data[vi] = content_id
vi = vi + 1
end
end
end
local firstrun = true
-- Global helpers for mapgens
multi_map.c_ignore = nil
@ -153,6 +164,7 @@ multi_map.c_water = nil
multi_map.c_lava = nil
multi_map.c_bedrock = nil
multi_map.c_skyrock = nil
multi_map.c_shadow_caster = nil
minetest.register_on_mapgen_init(function(mapgen_params)
if multi_map.number_of_layers * multi_map.layer_height > multi_map.map_height then
@ -171,6 +183,7 @@ minetest.register_on_generated(function(minp, maxp)
multi_map.c_lava = minetest.get_content_id("default:lava_source")
multi_map.c_bedrock = minetest.get_content_id(multi_map.bedrock)
multi_map.c_skyrock = minetest.get_content_id(multi_map.skyrock)
multi_map.c_shadow_caster = minetest.get_content_id("multi_map_core:shadow_caster")
firstrun = false
end
@ -192,6 +205,7 @@ minetest.register_on_generated(function(minp, maxp)
local vm_data = vm:get_data()
multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, multi_map.c_bedrock)
vm:set_data(vm_data)
vm:calc_lighting(false)
vm:write_to_map(false)
@ -205,25 +219,55 @@ minetest.register_on_generated(function(minp, maxp)
local vm_data = vm:get_data()
multi_map.generate_singlenode_chunk(minp, maxp, area, vm_data, multi_map.c_skyrock)
vm:set_lighting({day=15, night=0})
vm:set_data(vm_data)
vm:calc_lighting(false)
vm:write_to_map(false)
else
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local vm_data = vm:get_data()
local remove_shadow_caster = false
-- Add a temporary stone layer above the chunk to ensure caves are dark
if multi_map.get_absolute_centerpoint() >= maxp.y then
if vm_data[area:index(minp.x, maxp.y + 1, minp.z)] == multi_map.c_ignore then
remove_shadow_caster = true
multi_map.generate_singlenode_plane(minp, maxp, area, vm_data, maxp.y + 1, multi_map.c_shadow_caster)
end
end
local t = multi_map.generators[multi_map.current_layer]
if not t then
if multi_map.fallback_generator then
multi_map.fallback_generator.generator(multi_map.current_layer, minp, maxp, offset_minp, offset_maxp, multi_map.fallback_generator.arguments)
multi_map.fallback_generator.generator(multi_map.current_layer, vm, area, vm_data, minp, maxp, offset_minp, offset_maxp, multi_map.fallback_generator.arguments)
else
minetest.log("error", "Generator for layer "..multi_map.current_layer.." missing and no fallback specified, exiting mapgen!")
return
end
else
for i,f in ipairs(t) do
f.generator(multi_map.current_layer, minp, maxp, offset_minp, offset_maxp, f.arguments)
f.generator(multi_map.current_layer, vm, area, vm_data, minp, maxp, offset_minp, offset_maxp, f.arguments)
end
end
vm:set_data(vm_data)
vm:calc_lighting()
vm:write_to_map()
vm:update_liquids()
-- Remove the temporary stone shadow casting layer again, if needed
if remove_shadow_caster then
if vm_data[area:index(minp.x, maxp.y + 1, minp.z)] == multi_map.c_shadow_caster then
multi_map.generate_singlenode_plane(minp, maxp, area, vm_data, maxp.y + 1, multi_map.c_ignore)
vm:set_data(vm_data)
vm:write_to_map()
end
end
end
end)
@ -239,6 +283,17 @@ minetest.register_node("multi_map_core:skyrock", {
paramtype = "light",
})
minetest.register_node("multi_map_core:shadow_caster", {
description = "Multi Map Shadow Caster",
drawtype = "airlike",
is_ground_content = false,
sunlight_propagates = false,
walkable = false,
pointable = false,
diggable = false,
climbable = false,
})
minetest.register_node("multi_map_core:bedrock", {
description = "Multi Map Impenetrable Bedrock",
drawtype = "normal",
@ -250,7 +305,7 @@ minetest.register_node("multi_map_core:bedrock", {
climbable = false,
})
--[[
function multi_map.calc_lighting(emin, emax, minp, maxp, propagate_shadow, ground_level)
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
multi_map.propagate_sunlight(vm, emin, emax, propagate_shadow, ground_level)
@ -312,7 +367,7 @@ function BitAND(a,b)--Bitwise and
end
return c
end
]]--
--[[
VoxelArea a(nmin, nmax);

View File

@ -99,7 +99,7 @@ local nobj_spike = nil
-- On generated function
function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_maxp)
function mmgen_levels.generate(current_layer, vm, area, data, minp, maxp, offset_minp, offset_maxp)
local x1 = maxp.x
local y1 = maxp.y
local z1 = maxp.z
@ -109,11 +109,6 @@ function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_ma
local oy1 = offset_maxp.y
local oy0 = offset_minp.y
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
local data = vm:get_data()
local light_data = vm:get_light_data()
local c_stone = minetest.get_content_id("default:stone")
local c_sand = minetest.get_content_id("default:sand")
local c_water = minetest.get_content_id("default:water_source")
@ -233,14 +228,6 @@ function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_ma
end
end
-- if relative_y < 0 then
-- if relative_y > -15 then
-- light_data[vi] = 15 + relative_y
-- else
-- light_data[vi] = 0
-- end
-- end
ni3d = ni3d + 1
ni2d = ni2d + 1
vi = vi + 1
@ -251,13 +238,4 @@ function mmgen_levels.generate(current_layer, minp, maxp, offset_minp, offset_ma
ni2d = ni2d + sidelen
end
vm:set_data(data)
-- vm:set_light_data(light_data)
-- if oy0 < 0 then
-- vm:set_lighting({day=0, night=0})
-- end
multi_map.calc_lighting(minp, maxp, minp, maxp, true)
vm:write_to_map()
vm:update_liquids()
end