Last active
March 9, 2022 00:43
-
-
Save kaeza/e88d6e8c868aa1ce81a3be50ea404afc to your computer and use it in GitHub Desktop.
Minetest - texutil.lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
-- Work with textures as if they were objects. | |
-- | |
-- All methods sanitize its arguments and perform any kind of | |
-- escaping needed. | |
-- | |
-- A simple example: | |
-- | |
-- local tex = texutil.new("foo.png"):colorize("#FF0000", 255) | |
-- tex:add(texutil.new("bar.png"):colorize("#0000FF", 255)) | |
-- print(tex) | |
-- --> (foo.png^[colorize:#FF0000FF:255^(bar.png^[colorize:#0000FFFF:255)) | |
-- | |
-- @module texutil | |
local M = { } | |
local F = string.format | |
--- | |
-- Table representing a texture. | |
-- | |
-- Integer indices are sub-textures. | |
local texture = { } | |
texture.__index = texture | |
-- INTERNAL | |
-- Escapes top-level characters that the texture parser | |
-- considers "special". | |
-- Returns escaped string. | |
local function escape(x) | |
return (x:gsub("([%[%]\\^%(%)])", "\\%1")) | |
end | |
-- INTERNAL | |
-- Adds an item and returns self. | |
function addraw(self, x) | |
self[#self+1] = x | |
return self | |
end | |
--- | |
-- Adds sub-textures to this texture. | |
-- | |
-- @tparam string|texture ... Textures to add. | |
-- @treturn texture This object. | |
function texture:add(...) | |
local t = { n=select("#", ...), ... } | |
for i = 1, t.n do | |
local x = t[i] | |
if type(x) == "string" then | |
x = escape(x) | |
end | |
addraw(self, x) | |
end | |
return self | |
end | |
-- TODO | |
local named_colors = { } | |
-- INTERNAL | |
-- Convert a string of hex digits to a number. | |
local function X(x) | |
return tonumber(x, 16) | |
end | |
-- INTERNAL | |
-- Parse a color into separate components. | |
-- Returns `r`, `g`, `b`, `a`. | |
-- Returns nil plus error message on error. | |
local function parse_color(x) | |
if type(x) == "string" then | |
-- #RRGGBBAA | |
local r, g, b, a | |
r, g, b, a = x:match("^#(%x%x)(%x%x)(%x%x)(%x%x)$") | |
if r then | |
return X(r), X(g), X(b), X(a) | |
end | |
-- #RRGGBB | |
r, g, b = x:match("^#(%x%x)(%x%x)(%x%x)$") | |
if r then | |
return X(r), X(g), X(b), 255 | |
end | |
local c | |
-- namedcolor[#alpha] | |
c, a = x:match("^([A-Za-z0-9]+)#(%x%x)$") | |
if not c then | |
c, a = x, 255 | |
else | |
a = X(a) | |
end | |
c = named_colors[c] | |
if c then | |
r, g, b = unpack(c) | |
return r, g, b, a | |
end | |
elseif type(x) == "number" then | |
-- 0xAARRGGBB | |
local a, r, g, b | |
a = math.floor(x/0x1000000)%0x100 | |
r = math.floor(x/0x10000)%0x100 | |
g = math.floor(x/0x100)%0x100 | |
b = math.floor(x)%0x100 | |
return r, g, b, a | |
end | |
return nil, "invalid color" | |
end | |
-- INTERNAL | |
-- Normalizes color argument and returns the normalized form | |
-- as a string in the format `#RRGGBBAA`. | |
local function norm_color(x) | |
local r, g, b, a = parse_color(x) | |
if not r then return nil, g end | |
return ("#%02X%02X%02X%02X"):format(r, g, b, a) | |
end | |
--- | |
-- Colorizes this texture. | |
-- | |
-- @tparam string|number color Base color. If it's a number, it must | |
-- be in the `0xRRGGBBAA` format. If it's a string, it must have the | |
-- format `#RRGGBBAA` or `#RRGGBB`. | |
-- @tparam ?string|number ratio Blend ratio. If it's a number, it must | |
-- be an integer in the range 0 to 255, inclusive, where 0 means no | |
-- colorization takes place, and 255 means the texture is fully | |
-- colorized. | |
-- @treturn texture This object. | |
function texture:colorize(color, ratio) | |
color = assert(norm_color(color)) | |
if type(ratio) == "number" then | |
ratio = ":"..math.max(0, math.min(255, math.floor(ratio))) | |
elseif ratio == "alpha" then | |
ratio = ":alpha" | |
else | |
ratio = "" | |
end | |
return addraw(self, "[colorize:"..color..ratio) | |
end | |
--- | |
-- Creates a new sub-texture combining the one or more textures. | |
-- | |
-- @tparam number w Width of new texture. | |
-- @tparam number h Height of new texture. | |
-- @tparam table textures List of textures to combine. It must be | |
-- an array where each item is a table `{x, y, tex}`, where `x` and | |
-- `y` are the coordinates where the texture is placed (relative | |
-- to the new texture's origin), and `tex` is the texture to add. | |
-- `tex` may be a string or another `texture` object. | |
-- @treturn texture This object. | |
function texture:combine(w, h, textures) | |
local t = { } | |
for i, tt in ipairs(textures) do | |
local x, y, texture = unpack(tt) | |
t[i] = x..","..y.."="..texture:gsub(":", "\\:") | |
end | |
return addraw(self, "[combine:"..w.."x"..h..":"..table.concat(t, ":")) | |
end | |
--- | |
-- Resizes this texture, scaling the contents. | |
-- | |
-- @tparam number w New width. | |
-- @tparam number h New height. | |
-- @treturn texture This object. | |
function texture:resize(w, h) | |
return addraw(self, "[resize:"..w.."x"..h) | |
end | |
--- | |
-- Returns a string representation of this object. | |
-- | |
-- @function texture:tostring | |
-- @treturn string A string. | |
-- @see texture:__tostring | |
texture.tostring = tostring | |
--- | |
-- Returns a string representation of this object. | |
-- | |
-- The string representation is the texture string that should be | |
-- used to get the texture represented by this object. | |
-- | |
-- This metamethod is called by the built-in `tostring` function. | |
-- | |
-- @treturn string A string. | |
function texture:__tostring() | |
local t = { } | |
for i, v in ipairs(self) do | |
t[i] = tostring(v) | |
end | |
return "("..table.concat(t, "^")..")" | |
end | |
--- | |
-- Create a new texture object. | |
-- | |
-- @tparam ?string|texture ... Initial sub-textures. | |
-- @treturn texture A new texture object. | |
function M.new(...) | |
local self = setmetatable({ }, texture) | |
self:add(...) | |
return self | |
end | |
return M |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment