mirror of
https://gitlab.com/gaelysam/mapgen_rivers.git
synced 2024-11-14 06:40:21 +01:00
74733549df
Now working in pure Lua! Some parts of the code are very hacky (e.g. noise) and the way new and old codes have been glued together is sometimes to be rewritten. But at least it works.
222 lines
4.7 KiB
Lua
222 lines
4.7 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+1
|
|
elseif d == 2 then
|
|
inext = iw+X
|
|
elseif d == 3 then
|
|
inext = iw-1
|
|
elseif d == 4 then
|
|
inext = iw-X
|
|
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
|