2020-04-14 21:11:54 +02:00
mapgen_rivers = { }
2020-04-09 21:13:38 +02:00
2020-04-14 21:11:54 +02:00
local modpath = minetest.get_modpath ( minetest.get_current_modname ( ) ) .. ' / '
2020-04-09 21:13:38 +02:00
2020-04-14 21:11:54 +02:00
dofile ( modpath .. ' settings.lua ' )
2020-04-09 21:13:38 +02:00
2020-04-14 21:11:54 +02:00
local blocksize = mapgen_rivers.blocksize
local sea_level = mapgen_rivers.sea_level
local riverbed_slope = mapgen_rivers.riverbed_slope
2020-04-12 09:40:10 +02:00
2020-04-14 21:11:54 +02:00
local make_polygons = dofile ( modpath .. ' polygons.lua ' )
2020-04-12 09:40:10 +02:00
2020-04-14 21:11:54 +02:00
local transform_quadri = dofile ( modpath .. ' geometry.lua ' )
2020-04-09 21:13:38 +02:00
2020-04-26 17:13:38 +02:00
-- Linear interpolation
2020-04-13 10:31:38 +02:00
local function interp ( v00 , v01 , v11 , v10 , xf , zf )
2020-04-12 09:40:10 +02:00
local v0 = v01 * xf + v00 * ( 1 - xf )
local v1 = v11 * xf + v10 * ( 1 - xf )
2020-04-09 21:13:38 +02:00
return v1 * zf + v0 * ( 1 - zf )
end
local data = { }
local function generate ( minp , maxp , seed )
local c_stone = minetest.get_content_id ( " default:stone " )
local c_dirt = minetest.get_content_id ( " default:dirt " )
local c_lawn = minetest.get_content_id ( " default:dirt_with_grass " )
local c_sand = minetest.get_content_id ( " default:sand " )
local c_water = minetest.get_content_id ( " default:water_source " )
local c_rwater = minetest.get_content_id ( " default:river_water_source " )
local vm , emin , emax = minetest.get_mapgen_object ( " voxelmanip " )
vm : get_data ( data )
local a = VoxelArea : new ( { MinEdge = emin , MaxEdge = emax } )
local ystride = a.ystride -- Tip : the ystride of a VoxelArea is the number to add to the array index to get the index of the position above. It's faster because it avoids to completely recalculate the index.
2020-04-13 15:01:54 +02:00
2020-04-14 21:11:54 +02:00
local polygons = make_polygons ( minp , maxp )
2020-04-09 21:13:38 +02:00
2020-04-12 16:42:03 +02:00
local i = 1
for x = minp.x , maxp.x do
for z = minp.z , maxp.z do
2020-04-13 09:54:04 +02:00
local poly = polygons [ i ]
if poly then
2020-04-14 21:11:54 +02:00
local xf , zf = transform_quadri ( poly.x , poly.z , x / blocksize , z / blocksize )
2020-04-12 16:42:03 +02:00
local i00 , i01 , i11 , i10 = unpack ( poly.i )
2020-04-09 21:13:38 +02:00
2020-04-26 22:19:05 +02:00
-- Load river width on 4 edges and corners
2020-04-13 12:15:10 +02:00
local r_west , r_north , r_east , r_south = unpack ( poly.rivers )
2020-04-26 22:19:05 +02:00
local c_NW , c_NE , c_SE , c_SW = unpack ( poly.river_corners )
-- Calculate the depth factor for each edge and corner.
-- Depth factor:
-- < 0: outside river
-- = 0: on riverbank
-- > 0: inside river
local depth_factors = {
r_west - xf ,
r_north - zf ,
xf - r_east ,
zf - r_south ,
c_NW - xf - zf ,
2020-04-27 21:08:15 +02:00
xf - zf - c_NE ,
xf + zf - c_SE ,
zf - xf - c_SW ,
2020-04-26 22:19:05 +02:00
}
-- Find the maximal depth factor and determine to which river it belongs
local depth_factor_max = 0
local imax = 0
for i = 1 , 8 do
if depth_factors [ i ] >= depth_factor_max then
depth_factor_max = depth_factors [ i ]
imax = i
2020-04-13 15:01:54 +02:00
end
end
2020-04-26 22:19:05 +02:00
-- Transform the coordinates to have xf and zf = 0 or 1 in rivers (to avoid rivers having lateral slope and to accomodate the surrounding smoothly)
if imax == 0 then
2020-04-27 21:08:15 +02:00
local x0 = math.max ( r_west , c_NW - zf , zf - c_SW )
local x1 = math.min ( r_east , c_NE + zf , c_SE - zf )
local z0 = math.max ( r_north , c_NW - xf , xf - c_NE )
local z1 = math.min ( r_south , c_SW + xf , c_SE - xf )
2020-04-26 22:19:05 +02:00
xf = ( xf - x0 ) / ( x1 - x0 )
zf = ( zf - z0 ) / ( z1 - z0 )
elseif imax == 1 then
xf = 0
elseif imax == 2 then
zf = 0
elseif imax == 3 then
xf = 1
elseif imax == 4 then
zf = 1
elseif imax == 5 then
xf , zf = 0 , 0
elseif imax == 6 then
xf , zf = 1 , 0
elseif imax == 7 then
xf , zf = 1 , 1
elseif imax == 8 then
xf , zf = 0 , 1
2020-04-13 12:15:10 +02:00
end
2020-04-26 22:19:05 +02:00
-- Determine elevation by interpolation
2020-04-13 10:31:38 +02:00
local vdem = poly.dem
2020-04-13 12:27:24 +02:00
local terrain_height = math.floor ( 0.5 + interp (
2020-04-13 10:31:38 +02:00
vdem [ 1 ] ,
vdem [ 2 ] ,
vdem [ 3 ] ,
vdem [ 4 ] ,
2020-04-09 21:13:38 +02:00
xf , zf
) )
2020-04-14 17:53:36 +02:00
local lake_height = math.max ( math.floor ( poly.lake ) , terrain_height )
2020-04-26 22:19:05 +02:00
if imax > 0 and depth_factor_max > 0 then
terrain_height = math.min ( math.max ( lake_height , sea_level ) - math.floor ( 1 + depth_factor_max * riverbed_slope ) , terrain_height )
2020-04-14 17:53:36 +02:00
end
2020-04-09 21:13:38 +02:00
local is_lake = lake_height > terrain_height
local ivm = a : index ( x , minp.y - 1 , z )
if terrain_height >= minp.y then
for y = minp.y , math.min ( maxp.y , terrain_height ) do
if y == terrain_height then
if is_lake or y <= sea_level then
data [ ivm ] = c_sand
else
data [ ivm ] = c_lawn
end
else
data [ ivm ] = c_stone
end
ivm = ivm + ystride
end
end
if lake_height > sea_level then
if is_lake and lake_height > minp.y then
for y = math.max ( minp.y , terrain_height + 1 ) , math.min ( maxp.y , lake_height ) do
data [ ivm ] = c_rwater
ivm = ivm + ystride
end
end
else
for y = math.max ( minp.y , terrain_height + 1 ) , math.min ( maxp.y , sea_level ) do
data [ ivm ] = c_water
ivm = ivm + ystride
end
end
end
2020-04-12 16:42:03 +02:00
i = i + 1
2020-04-09 21:13:38 +02:00
end
end
vm : set_data ( data )
minetest.generate_ores ( vm , minp , maxp )
vm : set_lighting ( { day = 0 , night = 0 } )
vm : calc_lighting ( )
vm : update_liquids ( )
vm : write_to_map ( )
end
minetest.register_on_generated ( generate )