texgen/init.lua

136 lines
4.8 KiB
Lua

local modname = "texgen"
local modpath = minetest.get_modpath(modname)
-- Rewrite mod.conf on startup; register_on_mods_loaded does not work
do
local conf = Settings(modpath .. "/mod.conf")
conf:set("name", modname)
conf:set("description", "Dynamically generated texture packs")
conf:set("depends", "modlib")
local to_depend = {}
local to_dep_list = {}
for _, modname in pairs(minetest.get_modnames()) do to_depend[modname] = true end -- luacheck: ignore
local opt_dep_str = conf:get"optional_depends" or ""
for opt_depend in opt_dep_str:gmatch"[^%s,]+" do
table.insert(to_dep_list, opt_depend)
to_depend[opt_depend] = nil
end
to_depend.texgen = nil -- no circular dependency
to_depend.modlib = nil -- modlib is already a hard dependency
if next(to_depend) or not modlib then
for dep in pairs(to_depend) do table.insert(to_dep_list, dep) end
conf:set("optional_depends", table.concat(to_dep_list, ", "))
conf:write()
error"mod.conf updated to optionally depend on all enabled mods, please restart the game"
end
end
assert(modlib.version >= 96, "update modlib to version rolling-96 or newer")
local texture_path = modpath .. "/textures/"
if minetest.rmdir then
-- Clear texture directory on startup
minetest.rmdir(texture_path, true)
end
minetest.mkdir(texture_path)
local media = modlib.minetest.media
local function get_path(filename)
local path
local mod = media.mods[filename]
if mod == modname then -- media overridden by this mod
local overridden_paths = media.overridden_paths[filename]
if not overridden_paths then return end
path = overridden_paths[#overridden_paths]
else
path = media.paths[filename]
end
return path
end
texgen = {} -- HACK only use the mod namespace to expose the dithering methods to the schema...
local dithering = modlib.mod.include"dithering.lua" -- sets texgen.dithering_methods
local conf, schema = modlib.mod.configuration()
-- Register palette downloading command if HTTP API is available; this reloads the schema
local insecure_env, http = minetest.request_insecure_environment(), minetest.request_http_api()
if insecure_env and http then
assert(loadfile(modlib.mod.get_resource"download_palette.lua"))(insecure_env, http, schema)
end
texgen = nil -- ...delete it afterwards
local palette, dither
if conf.palette.name then
palette = modlib.mod.include"palette.lua"(conf.palette.name)
dither = dithering(conf.palette.dithering)
end
local saturate, monochrome, invert = conf.saturate, conf.monochrome, conf.invert
local average
if conf.average then
average = modlib.mod.include"average_color.lua"
end
local function read_convert_png(path)
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)
return png
end
local clamp = modlib.math.clamp
local function transform_png(filename, path)
local png = read_convert_png(path)
if palette then
dither(png, palette)
end
modlib.table.map(png.data, function(color_num)
local color = modlib.minetest.colorspec.from_number(color_num)
if saturate ~= 1 then
-- See https://alienryderflex.com/saturation.html
local P = math.sqrt(0.299 * color.r^2 + 0.587 * color.g^2 + 0.114 * color.b^2)
local res = modlib.vector.apply({
r = clamp((color.r - P) * saturate + P + 0.5, 0, 255),
g = clamp((color.g - P) * saturate + P + 0.5, 0, 255),
b = clamp((color.b - P) * saturate + P + 0.5, 0, 255),
}, math.floor)
color.r, color.g, color.b = res.r, res.g, res.b
end
if invert then
color.r, color.g, color.b = 255 - color.r, 255 - color.g, 255 - color.b
end
if monochrome then
local brightness = math.floor(0.299 * color.r + 0.587 * color.g + 0.114 * color.b + 0.5)
color.r, color.g, color.b = brightness, brightness, brightness
end
return color:to_number()
end)
local width, height, data = png.width, png.height, png.data
if average then
width, height, data = 1, 1, {average(png):to_number()}
end
modlib.file.write(modlib.file.concat_path{modpath, "textures", filename},
modlib.minetest.encode_png(width, height, data))
end
for filename in pairs(media.paths) do
local _, ext = modlib.file.get_extension(filename)
if ext == "png" then
local path = get_path(filename)
-- May be (only) overridden media from this mod, which does not have a path (as it was deleted)
if path then transform_png(filename, path) end
end
end
-- Builtin textures aren't provided by mods and are thus unknown to modlib; provide them through this mod
for _, filename in ipairs(minetest.get_dir_list(modlib.file.concat_path{modpath, "builtin"}, false)) do
-- Don't override builtin overrides by other mods
if filename:match"%.png$" and not (media.paths[filename] and media.overridden_paths[filename]) then
transform_png(filename, modlib.file.concat_path{modpath, "builtin", filename})
end
end