sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
12.2 kB
if const.BiomeTileSize then
DefineMapGrid("BiomeGrid", 16, const.BiomeTileSize, 64, config.EditableBiomeGrid and "save_in_map")
end
local max_value = 254
local height_scale = const.TerrainHeightScale
local height_max = const.MaxTerrainHeight
local type_tile = const.TypeTileSize
local wd_max = const.RandomMap.BiomeMaxWaterDist
local h_max, h_scale = height_max/height_scale, guim/height_scale
local min_sl, max_sl = const.RandomMap.BiomeMinSeaLevel/height_scale, const.RandomMap.BiomeMaxSeaLevel/height_scale
assert(guim % height_scale == 0)
BiomeMatchParams = {
{ id = "Height", name = "Height", units = "(m)", min = 0, max = h_max, default = 0, scale = h_scale, help = "Absolute height value on the map" },
{ id = "Slope", name = "Slope", units = "(deg)", min = 0, max = 90*60, default = 0, scale = 60, help = "Slope angle: 0 flat, 90 vertical" },
{ id = "Wet", name = "Humidity", units = "(%)", min = 0, max = 100, default = 50, help = "Humidity % derived from erosion intensity" },
{ id = "Hardness", name = "Soil Hardness", units = "(%)", min = 0, max = 100, default = 0, scale = 1, help = "Defines how much rigid is the soil agains erosion: 100% is solid rock without any erosion" },
{ id = "Orient", name = "Orientation", min = 0, max = 1000, default = 0, scale = 1000, help = "Slope orientation towards the sun: 0 Shadow, 1 Sunlit" },
{ id = "SeaLevel", name = "Sea Level", units = "(m)", min = min_sl, max = max_sl, default = max_sl, scale = h_scale, help = "Height above or below Sea Level set it MapData" },
{ id = "WaterDist", name = "Water Dist", units = "(m)", min = -wd_max, max = wd_max, default = wd_max, scale = guim, help = "Distance in (-) or out (+) the water border line" },
}
function BiomeWaterDist(water_grid)
if not water_grid then return end
local dist_out = GridDest(water_grid)
if GridIsFlat(water_grid) then
local value = GridGet(water_grid, 0, 0)
dist_out:clear(value == 0 and wd_max or -wd_max)
return dist_out
end
GridInvert(water_grid)
GridDistance(water_grid, dist_out, type_tile, wd_max)
GridInvert(water_grid)
local dist_in = GridDest(water_grid)
GridDistance(water_grid, dist_in, type_tile, wd_max)
local dist = GridAddMulDiv(dist_out, dist_in, -1)
return dist
end
function BiomeMatchItems()
local items = {}
for _, param in ipairs(BiomeMatchParams) do
items[#items + 1] = { value = param.id , text = param.name }
end
return items
end
DefineClass.Biome = {
__parents = { "Preset", },
properties = {
{ category = "Biome", id = "grid_value", name = "Grid Value", editor = "number", default = 0, min = 0, max = max_value, read_only = true, help = "Value stored in the Biome grid" },
{ category = "Biome", id = "palette_color", name = "Palette Color", editor = "color", default = -16777216, },
{ category = "Prefabs", id = "PrefabTypeWeights", name = "Prefab Types", editor = "nested_list", default = false, base_class = "BiomePrefabTypeWeight", inclusive = true },
{ category = "Prefabs", id = "FilteredPrefabsPreview", name = "Filtered Prefabs", editor = "number", default = 0, dont_save = true, read_only = true, },
{ category = "Prefabs", id = "TypeMixingPreset", name = "Mixing Pattern", editor = "preset_id", default = "", preset_class = "NoisePreset", },
{ category = "Prefabs", id = "TypeMixingPreview", name = "Mixing Preview", editor = "grid", default = false, no_edit = function(self) return self.TypeMixingPreset == "" end, frame = 1, min = 512, dont_save = true, read_only = true },
{ category = "Matching", id = "CompareParam", name = "Compare Param", editor = "set", default = empty_table, items = BiomeMatchItems, max_items_in_set = 1, dont_save = true },
},
EditorMenubarName = "Biomes",
EditorMenubar = "Map.Generate",
EditorIcon = "CommonAssets/UI/Icons/biology plants seed.png",
EditorView = Untranslated("<id> <color 0 128 0><grid_value></color>"),
StoreAsTable = false,
}
for _, match in ipairs(BiomeMatchParams) do
local maxw = 200
local id, name, units, min, max, scale, help = match.id, match.name, match.units or "", match.min, match.max, match.scale, match.help
local function no_edit(self)
local cmp_id = self:GetCompareId()
return cmp_id and cmp_id ~= id
end
table.iappend(Biome.properties, {
{ category = "Matching", id = id .. "From", name = name .. " From " .. units, editor = "number", default = false, min = min, max = max, scale = scale, no_edit = no_edit, slider = true, recalc_curve = id, help = help },
{ category = "Matching", id = id .. "Best", name = name .. " Best " .. units, editor = "number", default = false, min = min, max = max, scale = scale, no_edit = no_edit, slider = true, recalc_curve = id, help = help },
{ category = "Matching", id = id .. "To", name = name .. " To " .. units, editor = "number", default = false, min = min, max = max, scale = scale, no_edit = no_edit, slider = true, recalc_curve = id, help = help },
{ category = "Matching", id = id .. "Weight", name = name .. " Weight", editor = "number", default = 100, min = 0, max = maxw, scale = 100, no_edit = no_edit, slider = true, recalc_curve = id },
{ category = "Matching", id = id .. "Curve", name = name .. " Curve", editor = "grid", default = false, dont_save = true, read_only = true, no_edit = no_edit, dont_normalize = true, frame = 1, help = help },
})
Biome["Get" .. id .. "Curve"] = function(self)
return self[id .. "Curve"] or self["CalcCurve" .. id](self)
end
Biome["CalcCurve" .. id] = function(self, notify)
local grid = self[id .. "Curve"]
local w, h = 256, 64
if not grid then
grid = NewComputeGrid(w, h, "U", 8)
self[id .. "Curve"] = grid
end
grid:clear()
local weight, x_from, x_best, x_to = self[id .. "Weight"], self[id .. "From"], self[id .. "Best"], self[id .. "To"]
local x0, x1 = x_from or min, x_to or max
if not x_best or x_best >= x0 and x_best <= x1 then
for gx = 0, w-1 do
local x = min + MulDivRound(max - min, gx, w - 1)
if x >= x0 and x <= x1 then
local wi = weight
if not x_best then
--
elseif x_from and x >= x0 and x < x_best then
wi = MulDivRound(weight, x - x0, x_best - x0)
elseif x_to and x <= x1 and x > x_best then
wi = MulDivRound(weight, x1 - x, x1 - x_best)
end
local gy = MulDivRound(h - 1, maxw - wi, maxw)
GridDrawColumn(grid, gx, gy, 255, 128)
end
end
end
if notify then
ObjModified(self)
end
return grid
end
end
AppendClass.MapDataPreset = { properties = {
{ category = "Random Map", id = "BiomeGroup", editor = "choice", default = "", items = PresetGroupsCombo("Biome") },
{ category = "Random Map", id = "HeightMin", editor = "number", default = 10 * guim, scale = "m", min = 0, max = height_max, slider = true, help = "Value corresponding to black grayscale level" },
{ category = "Random Map", id = "HeightMax", editor = "number", default = height_max - 10 * guim, scale = "m", min = 0, max = height_max, slider = true, help = "Value corresponding to white grayscale level" },
{ category = "Random Map", id = "WetMin", editor = "number", default = 0, scale = "%", min = 0, max = 100, slider = true, help = "Value corresponding to black grayscale level" },
{ category = "Random Map", id = "WetMax", editor = "number", default = 100, scale = "%", min = 0, max = 100, slider = true, help = "Value corresponding to white grayscale level" },
{ category = "Random Map", id = "SeaLevel", editor = "number", default = 0, scale = "m", min = 0, max = height_max, slider = true },
{ category = "Random Map", id = "SeaPreset", editor = "preset_id", default = false, preset_class = "WaterObjPreset" },
{ category = "Random Map", id = "SeaMinDist", editor = "number", default = 32*guim, scale = "m", min = 0 },
{ category = "Random Map", id = "MinBumpSlope", editor = "number", default = 10*60, scale = "deg", min = 0, max = 90*60, slider = true },
{ category = "Random Map", id = "MaxBumpSlope", editor = "number", default = 40*60, scale = "deg", min = 0, max = 90*60, slider = true },
}}
function Biome:GetCompareId()
return next(self.CompareParam)
end
function Biome:GetProperties()
local compare_id = self:GetCompareId()
if not compare_id then
return self.properties
end
local props = table.icopy(self.properties)
ForEachPreset("Biome", function(preset)
if self.id ~= preset.id and self.group == preset.group then
local id = preset.id .. "_Compare"
props[#props + 1] = { category = "Compare", id = id, name = preset.id, editor = "grid", default = false, dont_save = true, read_only = true, dont_normalize = true, frame = 1 },
rawset(self, "Get" .. id, function()
local getter = preset["Get" .. compare_id .. "Curve"]
return getter and getter(preset)
end)
end
end)
return props
end
function Biome:GetFilteredPrefabs()
local types = table.map(self.PrefabTypeWeights or empty_table, "PrefabType")
types = table.invert(types)
local result = {}
for i,prefab in ipairs(PrefabMarkers) do
if types[prefab.type] then
table.insert(result, prefab.name)
end
end
return result
end
function Biome:GetTypeMixingGrid(result, rand_seed, ptype_to_idx)
local preset = NoisePresets[self.TypeMixingPreset]
local weights = self.PrefabTypeWeights or empty_table
if not preset or #weights < 2 then
return false
end
local noise = GridDest(result)
rand_seed = rand_seed and BraidRandom(rand_seed) or 0
preset:GetNoise(rand_seed, noise)
local weights_sum = 0
for i=1,#weights do
weights_sum = weights_sum + weights[i].Weight
end
local marks = 0
local levels = GridLevels(noise)
local histogram = {}
for level, count in sorted_pairs(levels) do
histogram[#histogram + 1] = {count, level}
end
local w, h = noise:size()
local total_area = w * h
local mask = GridDest(noise)
local prev_level = -1
local function Mark(level)
marks = marks + 1
local idx = not ptype_to_idx and marks or ptype_to_idx[weights[marks].PrefabType] or 0
GridMask(noise, mask, prev_level + 1, level)
prev_level = level
GridPaint(result, mask, idx)
end
local idx, area, weight = 1, 0, 0
for i=1,#weights-1 do
weight = weight + weights[i].Weight
local target_area = MulDivRound(total_area, weight, weights_sum)
while idx <= #histogram do
local entry = histogram[idx]
area = area + entry[1]
idx = idx + 1
if area >= target_area then
Mark(entry[2])
break
end
end
end
Mark(max_int)
return result
end
function Biome:__paste(...)
local res = Preset.__paste(self, ...)
res.grid_value = nil
return res
end
function Biome:PostLoad()
self:AssignValue()
Preset.PostLoad(self)
end
function Biome:AssignValue()
if self.grid_value > 0 then return end
local value = 0
ForEachPreset("Biome", function(p)
value = Max(value, p.grid_value)
end)
if value < max_value then
self.grid_value = value + 1
return
end
local map = BiomeValueToPreset()
for i=1,max_value do
if not map[i] then
self.grid_value = i
return
end
end
assert(false, "No more biome grid values available!")
self.grid_value = -1
end
----
DefineClass.BiomePrefabTypeWeight = {
__parents = { "PropertyObject" },
properties = {
{ id = "PrefabType", name = "Type", editor = "preset_id", default = "", preset_class = "PrefabType" },
{ id = "Weight", name = "Weight", editor = "number", default = 100, min = 0, max = 100, slider = true },
},
EditorView = Untranslated("<PrefabType> (weight: <Weight>)"),
}
----
function BiomeValueToPreset()
local map = {}
ForEachPreset("Biome", function(preset, group, map)
local value = preset.grid_value
if value <= 0 then
--
elseif map[value] then
print("Biome value", value, "collision", map[value].id, "/", preset.group, "-", preset.id)
else
map[value] = preset
end
end, map)
return map
end
function DbgGetBiomePalette()
local palette = {}
ForEachPreset("Biome", function(preset)
palette[preset.grid_value] = preset.palette_color
end)
palette[255] = RGBA(255, 255, 255, 128)
return palette
end