texgen/palette.lua

43 lines
1.5 KiB
Lua

local function relative_color_distance(color, other_color)
-- See https://www.compuphase.com/cmetric.htm
local redmean = (color.r + other_color.r) / 2
-- Omits the square root as this only has to be relative
return (2 + redmean/256) * (color.r-other_color.r)^2
+ 4 * (color.g-other_color.g)^2
+ (2 + (255 - redmean)/256) * (color.b-other_color.b)^2
end
local palettes = modlib.mod.get_resource"palettes"
return function(name)
local path = modlib.file.concat_path{palettes, name .. ".png"}
local file = assert(io.open(path, "rb"))
local png = modlib.minetest.decode_png(file)
assert(not file:read(1), "EOF expected")
file:close()
modlib.minetest.convert_png_to_argb8(png)
local colors = {}
for _, color in pairs(png.data) do
-- TODO ignore colors with alpha 0?
local rgb = color % 0x1000000
colors[rgb] = true
end
local palette_colors = {}
for colornum in pairs(colors) do
table.insert(palette_colors, modlib.minetest.colorspec.from_number(colornum))
end
return function(color)
-- Find closest color using a linear search; a k-d-tree can't be employed here because the metric isn't euclidean
local closest_color = palette_colors[1]
local closest_distance = relative_color_distance(color, closest_color)
for i = 2, #palette_colors do
local palette_color = palette_colors[i]
local distance = relative_color_distance(color, palette_color)
-- TODO deal with same distances through random choice?
if distance < closest_distance then
closest_color = palette_color
closest_distance = distance
end
end
return closest_color
end
end