mirror of
https://gitlab.com/gaelysam/mapgen_rivers.git
synced 2024-11-10 20:50:19 +01:00
222 lines
4.5 KiB
Lua
222 lines
4.5 KiB
Lua
-- erosion.lua
|
|
|
|
local function erode(model, time)
|
|
--local tinsert = table.insert
|
|
local mmin, mmax = math.min, math.max
|
|
local dem = model.dem
|
|
local dirs = model.dirs
|
|
local lakes = model.lakes
|
|
local rivers = model.rivers
|
|
local sea_level = model.params.sea_level
|
|
local K = model.params.K
|
|
local m = model.params.m
|
|
local X, Y = dem.X, dem.Y
|
|
local scalars = type(K) == "number" and type(m) == "number"
|
|
|
|
local erosion_time
|
|
if model.params.variable_erosion then
|
|
erosion_time = {}
|
|
else
|
|
erosion_time = model.erosion_time or {}
|
|
end
|
|
|
|
if scalars then
|
|
for i=1, X*Y do
|
|
local etime = 1 / (K*rivers[i]^m)
|
|
erosion_time[i] = etime
|
|
lakes[i] = mmax(lakes[i], dem[i], sea_level)
|
|
end
|
|
else
|
|
for i=1, X*Y do
|
|
local etime = 1 / (K[i]*rivers[i]^m[i])
|
|
erosion_time[i] = etime
|
|
lakes[i] = mmax(lakes[i], dem[i], sea_level)
|
|
end
|
|
end
|
|
|
|
for i=1, X*Y do
|
|
local iw = i
|
|
local remaining = time
|
|
local new_elev
|
|
while true do
|
|
local inext = iw
|
|
local d = dirs[iw]
|
|
|
|
if d == 0 then
|
|
new_elev = lakes[iw]
|
|
break
|
|
elseif d == 1 then
|
|
inext = iw+X
|
|
elseif d == 2 then
|
|
inext = iw+1
|
|
elseif d == 3 then
|
|
inext = iw-X
|
|
elseif d == 4 then
|
|
inext = iw-1
|
|
end
|
|
|
|
local etime = erosion_time[iw]
|
|
if remaining <= etime then
|
|
local c = remaining / etime
|
|
new_elev = (1-c) * lakes[iw] + c * lakes[inext]
|
|
break
|
|
end
|
|
|
|
remaining = remaining - etime
|
|
iw = inext
|
|
end
|
|
|
|
dem[i] = mmin(dem[i], new_elev)
|
|
end
|
|
end
|
|
|
|
local function diffuse(model, time)
|
|
local mmax = math.max
|
|
local dem = model.dem
|
|
local X, Y = dem.X, dem.Y
|
|
local d = model.params.d
|
|
local dmax = d
|
|
if type(d) == "table" then
|
|
dmax = -math.huge
|
|
for i=1, X*Y do
|
|
dmax = mmax(dmax, d[i])
|
|
end
|
|
end
|
|
|
|
local diff = dmax * time
|
|
local niter = math.floor(diff) + 1
|
|
local ddiff = diff / niter
|
|
|
|
local temp = {}
|
|
for n=1, niter do
|
|
local i = 1
|
|
for y=1, Y do
|
|
local iN = (y==1) and 0 or -X
|
|
local iS = (y==Y) and 0 or X
|
|
for x=1, X do
|
|
local iW = (x==1) and 0 or -1
|
|
local iE = (x==X) and 0 or 1
|
|
temp[i] = (dem[i+iN]+dem[i+iE]+dem[i+iS]+dem[i+iW])*0.25 - dem[i]
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
for i=1, X*Y do
|
|
dem[i] = dem[i] + temp[i]*ddiff
|
|
end
|
|
end
|
|
-- TODO Test this
|
|
end
|
|
|
|
local modpath = ""
|
|
if minetest then
|
|
if minetest.global_exists('mapgen_rivers') then
|
|
modpath = mapgen_rivers.modpath .. "terrainlib_lua/"
|
|
else
|
|
modpath = minetest.get_modpath(minetest.get_current_modname()) .. "terrainlib_lua/"
|
|
end
|
|
end
|
|
|
|
local rivermapper = dofile(modpath .. "rivermapper.lua")
|
|
local gaussian = dofile(modpath .. "gaussian.lua")
|
|
|
|
local function flow(model)
|
|
model.dirs, model.lakes = rivermapper.flow_routing(model.dem, model.dirs, model.lakes, 'semirandom')
|
|
model.rivers = rivermapper.accumulate(model.dirs, model.rivers)
|
|
end
|
|
|
|
local function uplift(model, time)
|
|
local dem = model.dem
|
|
local X, Y = dem.X, dem.Y
|
|
local uplift_rate = model.params.uplift
|
|
if type(uplift_rate) == "number" then
|
|
local uplift_total = uplift_rate * time
|
|
for i=1, X*Y do
|
|
dem[i] = dem[i] + uplift_total
|
|
end
|
|
else
|
|
for i=1, X*Y do
|
|
dem[i] = dem[i] + uplift_rate[i]*time
|
|
end
|
|
end
|
|
end
|
|
|
|
local function noise(model, time)
|
|
local random = math.random
|
|
local dem = model.dem
|
|
local noise_depth = model.params.noise * 2 * time
|
|
local X, Y = dem.X, dem.Y
|
|
for i=1, X*Y do
|
|
dem[i] = dem[i] + (random()-0.5) * noise_depth
|
|
end
|
|
end
|
|
|
|
local function define_isostasy(model, ref, link)
|
|
ref = ref or model.dem
|
|
if link then
|
|
model.isostasy_ref = ref
|
|
return
|
|
end
|
|
|
|
local X, Y = ref.X, ref.Y
|
|
local ref2 = model.isostasy_ref or {X=X, Y=Y}
|
|
model.isostasy_ref = ref2
|
|
for i=1, X*Y do
|
|
ref2[i] = ref[i]
|
|
end
|
|
|
|
return ref2
|
|
end
|
|
|
|
local function isostasy(model)
|
|
local dem = model.dem
|
|
local X, Y = dem.X, dem.Y
|
|
local temp = {X=X, Y=Y}
|
|
local ref = model.isostasy_ref
|
|
for i=1, X*Y do
|
|
temp[i] = ref[i] - dem[i]
|
|
end
|
|
|
|
gaussian.gaussian_blur_approx(temp, model.params.compensation_radius, 4)
|
|
for i=1, X*Y do
|
|
dem[i] = dem[i] + temp[i]
|
|
end
|
|
end
|
|
|
|
local evol_model_mt = {
|
|
erode = erode,
|
|
diffuse = diffuse,
|
|
flow = flow,
|
|
uplift = uplift,
|
|
noise = noise,
|
|
isostasy = isostasy,
|
|
define_isostasy = define_isostasy,
|
|
}
|
|
|
|
evol_model_mt.__index = evol_model_mt
|
|
|
|
local defaults = {
|
|
K = 1,
|
|
m = 0.5,
|
|
d = 1,
|
|
variable_erosion = false,
|
|
sea_level = 0,
|
|
uplift = 10,
|
|
noise = 0.001,
|
|
compensation_radius = 50,
|
|
}
|
|
|
|
local function EvolutionModel(params)
|
|
params = params or {}
|
|
local o = {params = params}
|
|
for k, v in pairs(defaults) do
|
|
if params[k] == nil then
|
|
params[k] = v
|
|
end
|
|
end
|
|
o.dem = params.dem
|
|
return setmetatable(o, evol_model_mt)
|
|
end
|
|
|
|
return EvolutionModel
|