local color
color = sorcery.lib.class {
__tostring = function(self)
-- return minetest.rgba(
-- self.red,
-- self.green,
-- self.blue,
-- self.alpha
-- )
local hex = function(val)
return string.format('%02X',math.max(0,math.min(255,math.floor(val))))
end
local str = '#' ..
hex(self.red) ..
hex(self.green) ..
hex(self.blue)
if self.alpha then str = str .. hex(self.alpha) end
return str
end;
__add = function(self, other)
local sfac = (self.alpha or 255) / 255
local ofac = (other.alpha or 255) / 255
if self.alpha == other.alpha then
sfac = 1 ofac = 1
end
local sr, sg, sb = other.red * ofac, other.blue * ofac, other.green * ofac
local nr, ng, nb = self.red * sfac, self.blue * sfac, self.green * sfac
local saturate = function(a,b)
return math.max(0, math.min(255, a+b))
end
local alpha = nil
if self.alpha and other.alpha then
alpha = saturate(self.alpha or 255, other.alpha or 255)
end
return color(
saturate(sr, nr),
saturate(sg, ng),
saturate(sb, nb),
alpha
)
end;
cast = {
number = function(n) return {
red = n; green = n; blue = n;
} end;
table = function(t) return {
red = t[1]; green = t[2]; blue = t[3];
} end;
};
construct = function(r,g,b,a)
local clip = function(v)
return math.max(0,math.min(255,v))
end;
local warp = function(f)
return function(self, ...)
local n = color(self)
f(n, ...)
return n
end;
end;
local new = {
hex = function(self) return
getmetatable(self).__tostring(self)
end;
fmt = function(self, text) return
minetest.colorize(self:hex(), text)
end;
luminosity = function(self) return
(self.red + self.green + self.blue) / 3
end;
readable = function(self, target)
target = target or 200
local lum = self:luminosity()
if lum < target then
local f = 1.0 + (target - lum) / 255
local nc = self:brighten(f * 1.5)
-- i don't know why the *1.5 is necessary. it's
-- an ugly hack to work around broken math,
-- because i'm too much of a mathtard to actually
-- find what's wrong
return nc
else
return self
end
end;
bg = function(self, text) return
text .. minetest.get_background_escape_sequence(self:hex())
end;
fade = warp(function(new, fac)
new.alpha = math.min(255, (new.alpha or 255) * fac)
end);
brighten = warp(function(new, fac)
local lum = new:luminosity()
local newlum = lum * fac
local delta = (newlum - lum)
new.red = clip(new.red + delta)
new.blue = clip(new.blue + delta)
new.green = clip(new.green + delta)
end);
darken = warp(function(new, fac)
new.red = clip(new.red - (new.red * fac))
new.blue = clip(new.blue - (new.blue * fac))
new.green = clip(new.green - (new.green * fac))
end);
}
if g == nil then
if type(r) == 'string' then
assert(false) -- TODO parse color string
elseif type(r) == 'table' then
new.red = r[1]
new.green = r[2]
new.blue = r[3]
new.alpha = r[4]
else assert(false) end
else
new.red = r
new.green = g
new.blue = b
new.alpha = a
end
return new
end
}
return color