mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-26 09:03:01 +00:00
//noise2d: add sin; sort out apply_mode as number
This commit is contained in:
parent
49bf0f19bc
commit
1d82013d86
11 changed files with 105 additions and 33 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
|
||||||
|
|
||||||
--- Applies the given noise field to the given heightmap.
|
--- Applies the given noise field to the given heightmap.
|
||||||
-- Mutates the given heightmap.
|
-- Mutates the given heightmap.
|
||||||
|
@ -7,26 +9,41 @@
|
||||||
-- @param region_height number The height of the defined region.
|
-- @param region_height number The height of the defined region.
|
||||||
-- @param apply_mode string The apply mode to use to apply the noise to the heightmap.
|
-- @param apply_mode string The apply mode to use to apply the noise to the heightmap.
|
||||||
-- @returns bool[,string] A boolean value representing whether the application was successful or not. If false, then an error message as a string is also returned describing the error that occurred.
|
-- @returns bool[,string] A boolean value representing whether the application was successful or not. If false, then an error message as a string is also returned describing the error that occurred.
|
||||||
function worldeditadditions.noise.apply_2d(heightmap, noise, heightmap_size, region_height, apply_mode)
|
function worldeditadditions.noise.apply_2d(heightmap, noise, heightmap_size, pos1, pos2, apply_mode)
|
||||||
if type(apply_mode) ~= "string" then
|
if type(apply_mode) ~= "string" and type(apply_mode) ~= "number" then
|
||||||
return false, "Error: Expected string value for apply_mode, but received value of type "..type(apply_mode)
|
return false, "Error: Expected value of type string or number for apply_mode, but received value of type "..type(apply_mode)
|
||||||
end
|
end
|
||||||
|
|
||||||
local percent = tonumber(apply_mode:match("^(%d+)%%$"))
|
local region_height = pos2.y - pos1.y
|
||||||
|
|
||||||
|
print("NOISE\n")
|
||||||
|
worldeditadditions.format.array_2d(noise, heightmap_size.x)
|
||||||
|
|
||||||
|
|
||||||
|
local height = tonumber(apply_mode)
|
||||||
|
|
||||||
|
print("HEIGHT", height)
|
||||||
|
|
||||||
for z = heightmap_size.z - 1, 0, -1 do
|
for z = heightmap_size.z - 1, 0, -1 do
|
||||||
for x = heightmap_size.x - 1, 0, -1 do
|
for x = heightmap_size.x - 1, 0, -1 do
|
||||||
local i = (z * heightmap_size.x) + x
|
local i = (z * heightmap_size.x) + x
|
||||||
|
|
||||||
if apply_mode == "add" then
|
if apply_mode == "add" then
|
||||||
heightmap[i] = heightmap[i] + noise[i]
|
heightmap[i] = wea.round(heightmap[i] + noise[i])
|
||||||
elseif apply_mode == "multiply" then
|
elseif apply_mode == "multiply" then
|
||||||
heightmap[i] = heightmap[i] * noise[i]
|
heightmap[i] = wea.round(heightmap[i] * noise[i])
|
||||||
elseif percent then
|
elseif height then
|
||||||
-- Rescale from 0 - 1 to -1 - +1
|
-- Rescale from 0 - 1 to -1 - +1
|
||||||
local rescaled = (noise[i] * 2) - 1
|
local rescaled = (noise[i] * 2) - 1
|
||||||
-- Rescale to match the percentage specified
|
-- print("DEBUG x", x, "z", z, "rescaled 1", rescaled)
|
||||||
rescaled = rescaled * region_height * percent
|
-- Rescale to match the height specified
|
||||||
|
rescaled = rescaled * height
|
||||||
|
-- print("DEBUG x", x, "z", z, "rescaled 2", rescaled)
|
||||||
|
rescaled = math.floor(wea.clamp(
|
||||||
|
heightmap[i] + rescaled,
|
||||||
|
0, region_height
|
||||||
|
))
|
||||||
|
-- print("DEBUG x", x, "z", z, "before", heightmap[i], "after", rescaled)
|
||||||
heightmap[i] = rescaled
|
heightmap[i] = rescaled
|
||||||
else
|
else
|
||||||
return false, "Error: Unknown apply mode '"..apply_mode.."'"
|
return false, "Error: Unknown apply mode '"..apply_mode.."'"
|
||||||
|
|
7
worldeditadditions/lib/noise/engines/init.lua
Normal file
7
worldeditadditions/lib/noise/engines/init.lua
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
Perlin = dofile(wea.modpath.."/lib/noise/engines/perlin.lua"),
|
||||||
|
Sin = dofile(wea.modpath.."/lib/noise/engines/sin.lua")
|
||||||
|
}
|
22
worldeditadditions/lib/noise/engines/sin.lua
Normal file
22
worldeditadditions/lib/noise/engines/sin.lua
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
|
||||||
|
|
||||||
|
local Sin = {}
|
||||||
|
Sin.__index = Sin
|
||||||
|
|
||||||
|
|
||||||
|
function Sin.new()
|
||||||
|
local result = {}
|
||||||
|
setmetatable(result, Sin)
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
function Sin:noise( x, y, z )
|
||||||
|
-- local value = math.sin(x)
|
||||||
|
local value = (math.sin(x) + math.sin(y) + math.sin(z)) / 3
|
||||||
|
-- Rescale from -1 - +1 to 0 - 1
|
||||||
|
return (value + 1) / 2
|
||||||
|
-- return (
|
||||||
|
end
|
||||||
|
|
||||||
|
return Sin
|
|
@ -11,4 +11,4 @@ dofile(wea.modpath.."/lib/noise/make_2d.lua")
|
||||||
dofile(wea.modpath.."/lib/noise/params_apply_default.lua")
|
dofile(wea.modpath.."/lib/noise/params_apply_default.lua")
|
||||||
|
|
||||||
-- Noise generation engines
|
-- Noise generation engines
|
||||||
wea.noise.Perlin = dofile(wea.modpath.."/lib/noise/engines/perlin.lua")
|
wea.noise.engines = dofile(wea.modpath.."/lib/noise/engines/init.lua")
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
-- ██ ████ ██ ███████ █████ █████ █████ ██ ██
|
-- ██ ████ ██ ███████ █████ █████ █████ ██ ██
|
||||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
-- ██ ██ ██ ██ ██ ██ ███████ ███████ ███████ ██████
|
-- ██ ██ ██ ██ ██ ██ ███████ ███████ ███████ ██████
|
||||||
|
local wea = worldeditadditions
|
||||||
|
|
||||||
-- Generate a flat array of 2D noise.
|
-- Generate a flat array of 2D noise.
|
||||||
-- Written with help from https://www.redblobgames.com/maps/terrain-from-noise/
|
-- Written with help from https://www.redblobgames.com/maps/terrain-from-noise/
|
||||||
|
@ -18,7 +18,9 @@ function worldeditadditions.noise.make_2d(size, start_pos, params)
|
||||||
for i, layer in ipairs(params) do
|
for i, layer in ipairs(params) do
|
||||||
local generator
|
local generator
|
||||||
if layer.algorithm == "perlin" then
|
if layer.algorithm == "perlin" then
|
||||||
generator = worldeditadditions.noise.Perlin.new()
|
generator = wea.noise.engines.Perlin.new()
|
||||||
|
elseif layer.algorithm == "sin" then
|
||||||
|
generator = wea.noise.engines.Sin.new()
|
||||||
else -- We don't have any other generators just yet
|
else -- We don't have any other generators just yet
|
||||||
return false, "Error: Unknown noise algorithm '"..tostring(layer.algorithm).."' in layer "..i.." of "..#params.." (available algorithms: perlin)."
|
return false, "Error: Unknown noise algorithm '"..tostring(layer.algorithm).."' in layer "..i.." of "..#params.." (available algorithms: perlin)."
|
||||||
end
|
end
|
||||||
|
@ -39,14 +41,7 @@ function worldeditadditions.noise.make_2d(size, start_pos, params)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for x = 0, size.x do
|
-- We don't round here, because otherwise when we apply it it'll be inaccurate
|
||||||
for y = 0, size.z do
|
|
||||||
local i = y*size.x + x
|
|
||||||
result[i] = worldeditadditions.round(result[i])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
print("NOISE\n", worldeditadditions.format.array_2d(result, size.x))
|
|
||||||
|
|
||||||
return true, result
|
return true, result
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,7 @@ function worldeditadditions.noise.params_apply_default(params)
|
||||||
-- - The exact string "add": Noise values are added to each heightmap pixel.
|
-- - The exact string "add": Noise values are added to each heightmap pixel.
|
||||||
-- - The exact string "multiply": Each heightmap pixel is multiplied by the corresponding noise value.
|
-- - The exact string "multiply": Each heightmap pixel is multiplied by the corresponding noise value.
|
||||||
-- - A string in the form of digits followed by a percent sign (e.g. "40%"), then the noise will is remapped from the range 0 - 1 to the range -1 - +1, and then for each pixel in the heightmap will be altered at most the given percentage of the total height of the defined region.
|
-- - A string in the form of digits followed by a percent sign (e.g. "40%"), then the noise will is remapped from the range 0 - 1 to the range -1 - +1, and then for each pixel in the heightmap will be altered at most the given percentage of the total height of the defined region.
|
||||||
apply = "40%",
|
apply = 5,
|
||||||
-- The backend noise algorithm to use
|
-- The backend noise algorithm to use
|
||||||
algorithm = "perlin",
|
algorithm = "perlin",
|
||||||
-- Zooms in and out
|
-- Zooms in and out
|
||||||
|
@ -38,7 +38,8 @@ function worldeditadditions.noise.params_apply_default(params)
|
||||||
|
|
||||||
-- Keyword support
|
-- Keyword support
|
||||||
if params_el.perlin then params_el.algorithm = "perlin" end
|
if params_el.perlin then params_el.algorithm = "perlin" end
|
||||||
print("DEBUG params_el type", type(params_el), "RAW", params_el)
|
if params_el.sin then params_el.algorithm = "sin" end
|
||||||
|
|
||||||
-- Apply this table to fill in the gaps
|
-- Apply this table to fill in the gaps
|
||||||
worldeditadditions.table.apply(
|
worldeditadditions.table.apply(
|
||||||
params_el,
|
params_el,
|
||||||
|
|
|
@ -14,10 +14,10 @@ local wea = worldeditadditions
|
||||||
-- @param noise_params table A noise parameters table.
|
-- @param noise_params table A noise parameters table.
|
||||||
function worldeditadditions.noise.run2d(pos1, pos2, noise_params)
|
function worldeditadditions.noise.run2d(pos1, pos2, noise_params)
|
||||||
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
local region_height = pos1.y - pos2.y
|
|
||||||
-- pos2 will always have the highest co-ordinates now
|
-- pos2 will always have the highest co-ordinates now
|
||||||
|
|
||||||
-- Fill in the default params
|
-- Fill in the default params
|
||||||
|
print("DEBUG noise_params_custom ", wea.format.map(noise_params))
|
||||||
noise_params = worldeditadditions.noise.params_apply_default(noise_params)
|
noise_params = worldeditadditions.noise.params_apply_default(noise_params)
|
||||||
print("DEBUG noise_params[1] ", wea.format.map(noise_params[1]))
|
print("DEBUG noise_params[1] ", wea.format.map(noise_params[1]))
|
||||||
|
|
||||||
|
@ -38,11 +38,12 @@ function worldeditadditions.noise.run2d(pos1, pos2, noise_params)
|
||||||
noise_params)
|
noise_params)
|
||||||
if not success then return success, noisemap end
|
if not success then return success, noisemap end
|
||||||
|
|
||||||
|
local message
|
||||||
success, message = wea.noise.apply_2d(
|
success, message = wea.noise.apply_2d(
|
||||||
heightmap_new,
|
heightmap_new,
|
||||||
noisemap,
|
noisemap,
|
||||||
heightmap_size,
|
heightmap_size,
|
||||||
region_height,
|
pos1, pos2,
|
||||||
noise_params[1].apply
|
noise_params[1].apply
|
||||||
)
|
)
|
||||||
print("RETURNED apply_2d success", success, "message", message)
|
print("RETURNED apply_2d success", success, "message", message)
|
||||||
|
|
|
@ -87,6 +87,17 @@ function worldeditadditions.getsign(src)
|
||||||
else return src:match('-') and -1 or 1 end
|
else return src:match('-') and -1 or 1 end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Clamp a number to ensure it falls within a given range.
|
||||||
|
-- @param value number The value to clamp.
|
||||||
|
-- @param min number The minimum allowed value.
|
||||||
|
-- @param max number The maximum allowed value.
|
||||||
|
-- @returns number The clamped number.
|
||||||
|
function worldeditadditions.clamp(value, min, max)
|
||||||
|
if value < min then return min end
|
||||||
|
if value > max then return max end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
-- For Testing:
|
-- For Testing:
|
||||||
-- worldeditadditions = {}
|
-- worldeditadditions = {}
|
||||||
-- print(worldeditadditions.getsign('-y'))
|
-- print(worldeditadditions.getsign('-y'))
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
|
||||||
--- Parses a map of key-value pairs into a table.
|
--- Parses a map of key-value pairs into a table.
|
||||||
-- For example, "count 25000 speed 0.8 rate_erosion 0.006 doawesome true" would be parsed into
|
-- For example, "count 25000 speed 0.8 rate_erosion 0.006 doawesome true" would be parsed into
|
||||||
-- the following table: { count = 25000, speed = 0.8, rate_erosion = 0.006, doawesome = true }.
|
-- the following table: { count = 25000, speed = 0.8, rate_erosion = 0.006, doawesome = true }.
|
||||||
-- @param params_text string The string to parse.
|
-- @param params_text string The string to parse.
|
||||||
|
-- @param keywords string[] A list of keywords. Keywords can be present on their own without a value. If found, their value will be automatically set to bool true.
|
||||||
-- @returns table A table of key-value pairs parsed out from the given string.
|
-- @returns table A table of key-value pairs parsed out from the given string.
|
||||||
function worldeditadditions.parse.map(params_text)
|
function worldeditadditions.parse.map(params_text, keywords)
|
||||||
local result = {}
|
local result = {}
|
||||||
local parts = worldeditadditions.split(params_text, "%s+", false)
|
local parts = wea.split(params_text, "%s+", false)
|
||||||
|
|
||||||
local last_key = nil
|
local last_key = nil
|
||||||
|
local mode = "KEY"
|
||||||
for i, part in ipairs(parts) do
|
for i, part in ipairs(parts) do
|
||||||
if i % 2 == 0 then -- Lua starts at 1 :-/
|
print("PARSE_MAP | i", i, "MODE", mode, "PART", part)
|
||||||
|
if mode == "VALUE" then
|
||||||
-- Try converting to a number to see if it works
|
-- Try converting to a number to see if it works
|
||||||
local part_converted = tonumber(part)
|
local part_converted = tonumber(part)
|
||||||
if part_converted == nil then part_converted = part end
|
if part_converted == nil then part_converted = part end
|
||||||
|
@ -18,8 +22,16 @@ function worldeditadditions.parse.map(params_text)
|
||||||
if part_converted == "true" then part_converted = true end
|
if part_converted == "true" then part_converted = true end
|
||||||
if part_converted == "false" then part_converted = false end
|
if part_converted == "false" then part_converted = false end
|
||||||
result[last_key] = part
|
result[last_key] = part
|
||||||
|
mode = "KEY"
|
||||||
else
|
else
|
||||||
last_key = part
|
last_key = part
|
||||||
|
-- Keyword support
|
||||||
|
if wea.table.contains(keywords, last_key) then
|
||||||
|
print("IS KEYWORD")
|
||||||
|
result[last_key] = true
|
||||||
|
else
|
||||||
|
mode = "VALUE"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true, result
|
return true, result
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
-- @param tbl table The table to look in.
|
-- @param tbl table The table to look in.
|
||||||
-- @param target any The target to look for.
|
-- @param target any The target to look for.
|
||||||
-- @returns bool Whether the table contains the given target or not.
|
-- @returns bool Whether the table contains the given target or not.
|
||||||
local function contains(tbl, target)
|
local function table_contains(tbl, target)
|
||||||
for key, value in ipairs(tbl) do
|
for key, value in ipairs(tbl) do
|
||||||
if value == target then return true end
|
if value == target then return true end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,16 +12,22 @@ worldedit.register_command("noise2d", {
|
||||||
if params_text == "" then return true, {} end
|
if params_text == "" then return true, {} end
|
||||||
|
|
||||||
|
|
||||||
local success, map = worldeditadditions.parse.map(params_text)
|
local success, map = worldeditadditions.parse.map(params_text, {
|
||||||
|
-- Keywords
|
||||||
|
"perlin", "sin"
|
||||||
|
})
|
||||||
if not success then return success, map end
|
if not success then return success, map end
|
||||||
|
|
||||||
|
print("DEBUG noise_params raw ", wea.format.map(map))
|
||||||
|
|
||||||
|
|
||||||
if map.scale then
|
if map.scale then
|
||||||
map.scale = tonumber(map.scale)
|
map.scale = tonumber(map.scale)
|
||||||
map.scale = wea.Vector3.new(map.scale, map.scale, map.scale)
|
map.scale = wea.Vector3.new(map.scale, map.scale, map.scale)
|
||||||
elseif map.scalex or map.scaley or map.scalez then
|
elseif map.scalex or map.scaley or map.scalez then
|
||||||
map.scalex = tonumber(map.scalex) or 0
|
map.scalex = tonumber(map.scalex) or 1
|
||||||
map.scaley = tonumber(map.scaley) or 0
|
map.scaley = tonumber(map.scaley) or 1
|
||||||
map.scalez = tonumber(map.scalez) or 0
|
map.scalez = tonumber(map.scalez) or 1
|
||||||
map.scale = wea.Vector3.new(map.scalex, map.scaley, map.scalez)
|
map.scale = wea.Vector3.new(map.scalex, map.scaley, map.scalez)
|
||||||
end
|
end
|
||||||
if map.offsetx or map.offsety or map.offsetz then
|
if map.offsetx or map.offsety or map.offsetz then
|
||||||
|
|
Loading…
Reference in a new issue