Fix calls to other util functions from within util functions

This commit is contained in:
Thomas Goyne 2013-05-02 07:42:02 -07:00
parent 9bcc6efcc8
commit 1b96bf748f
2 changed files with 406 additions and 369 deletions

View File

@ -1,209 +1,242 @@
local utils = { local sformat = string.format
copy = function(tbl) local copy
copy = function(tbl)
return (function()
local _tbl_0 = { }
for k, v in pairs(tbl) do
_tbl_0[k] = v
end
return _tbl_0
end)()
end
local deep_copy
deep_copy = function(tbl)
local seen = { }
copy = function(val)
if type(tbl) ~= 'table' then
return val
end
if seen[tbl] then
return seen[val]
end
seen[val] = tbl
return (function() return (function()
local _tbl_0 = { } local _tbl_0 = { }
for k, v in pairs(tbl) do for k, v in pairs(val) do
_tbl_0[k] = v _tbl_0[k] = copy(v)
end end
return _tbl_0 return _tbl_0
end)() end)()
end,
deep_copy = function(tbl)
local seen = { }
local copy
copy = function(val)
if type(tbl) ~= 'table' then
return val
end
if seen[tbl] then
return seen[val]
end
seen[val] = tbl
return (function()
local _tbl_0 = { }
for k, v in pairs(val) do
_tbl_0[k] = copy(v)
end
return _tbl_0
end)()
end
return copy(tbl)
end,
ass_color = function(r, g, b)
return string.format("&H%02X%02X%02X&", b, g, r)
end,
ass_alpha = function(a)
return string.format("&H%02X&", a)
end,
ass_style_color = function(r, g, b, a)
return string.format("&H%02X%02X%02X%02X", a, b, g, r)
end,
extract_color = function(s)
local a, b, g, r
a, b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)(%x%x)')
if a then
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16)
end
b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)&')
if b then
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), 0
end
a = s:match('&H(%x%x)&')
if a then
return 0, 0, 0, tonumber(a, 16)
end
r, g, b, a = s:match('#(%x%x)(%x?%x?)(%x?%x?)(%x?%x?)')
if r then
return tonumber(r, 16), tonumber(g, 16) or 0, tonumber(b, 16) or 0, tonumber(a, 16) or 0
end
end,
alpha_from_style = function(scolor)
return ass_alpha(select(4, extract_color(scolor)))
end,
color_from_style = function(scolor)
local r, g, b = extract_color(scolor)
return ass_color(r or 0, g or 0, b or 0)
end,
HSV_to_RGB = function(H, S, V)
local r, g, b = 0, 0, 0
if S == 0 then
r = self:clamp(V * 255, 0, 255)
g = r
b = r
else
H = math.abs(H) % 360
local Hi = math.floor(H / 60)
local f = H / 60.0 - Hi
local p = V * (1 - S)
local q = V * (1 - f * S)
local t = V * (1 - (1 - f) * S)
if Hi == 0 then
r = V * 255.0
g = t * 255.0
b = p * 255.0
elseif Hi == 1 then
r = q * 255.0
g = V * 255.0
b = p * 255.0
elseif Hi == 2 then
r = p * 255.0
g = V * 255.0
b = t * 255.0
elseif Hi == 3 then
r = p * 255.0
g = q * 255.0
b = V * 255.0
elseif Hi == 4 then
r = t * 255.0
g = p * 255.0
b = V * 255.0
elseif Hi == 5 then
r = V * 255.0
g = p * 255.0
b = q * 255.0
else
error("math.floor(H % 360 / 60) should be [0, 6), is " .. tostring(Hi) .. "?")
end
end
return r, g, b
end,
HSL_to_RGB = function(H, S, L)
local r, g, b
H = math.abs(H) % 360
S = clamp(S, 0, 1)
L = clamp(L, 0, 1)
if S == 0 then
r = L
g = L
b = L
else
local Q
if L < 0.5 then
Q = L * (1.0 + S)
else
Q = L + S - (L * S)
end
local P = 2.0 * L - Q
local Hk = H / 360
local Tr, Tg, Tb
if Hk < 1 / 3 then
Tr = Hk + 1 / 3
Tg = Hk
Tb = Hk + 2 / 3
elseif Hk > 2 / 3 then
Tr = Hk - 2 / 3
Tg = Hk
Tb = Hk - 1 / 3
else
Tr = Hk + 1 / 3
Tg = Hk
Tb = Hk - 1 / 3
end
local get_component
get_component = function(T)
if T < 1 / 6 then
return P + ((Q - P) * 6.0 * T)
elseif 1 / 6 <= T and T < 1 / 2 then
return Q
elseif 1 / 2 <= T and T < 2 / 3 then
return P + ((Q - P) * (2 / 3 - T) * 6.0)
else
return P
end
end
r = get_component(Tr)
g = get_component(Tg)
b = get_component(Tb)
end
return math.floor(r * 255 + 0.5), math.floor(g * 255 + 0.5), math.floor(b * 255 + 0.5)
end,
trim = function(s)
return s:gsub('^%s*(.-)%s*$', '%1')
end,
headtail = function(s)
local a, b, head, tail = s:find('(.-)%s+(.*)')
if a then
return head, tail
else
return s, ''
end
end,
words = function(s)
return function()
if s == '' then
return
end
local head, tail = string.headtail(s)
s = tail
return head
end
end,
clamp = function(val, min, max)
if val < min then
return min
elseif val > max then
return max
else
return val
end
end,
interpolate = function(pct, min, max)
if pct <= 0 then
return min
elseif pct >= 1 then
return max
else
return pct * (max - min) + min
end
end,
interpolate_color = function(pct, first, last)
local r1, g1, b1 = extract_color(first)
local r2, g2, b2 = extract_color(last)
local r, g, b = interpolate(pct, r1, r2), interpolate(pct, g1, g2), interpolate(pct, b1, b2)
return ass_color(r, g, b)
end,
interpolate_alpha = function(pct, first, last)
return ass_alpha(interpolate(pct, select(4, extract_color(first)), select(4, extract_color(last))))
end end
return copy(tbl)
end
local ass_color
ass_color = function(r, g, b)
return sformat("&H%02X%02X%02X&", b, g, r)
end
local ass_alpha
ass_alpha = function(a)
return sformat("&H%02X&", a)
end
local ass_style_color
ass_style_color = function(r, g, b, a)
return sformat("&H%02X%02X%02X%02X", a, b, g, r)
end
local extract_color
extract_color = function(s)
local a, b, g, r
a, b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)(%x%x)')
if a then
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16)
end
b, g, r = s:match('&H(%x%x)(%x%x)(%x%x)&')
if b then
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), 0
end
a = s:match('&H(%x%x)&')
if a then
return 0, 0, 0, tonumber(a, 16)
end
r, g, b, a = s:match('#(%x%x)(%x?%x?)(%x?%x?)(%x?%x?)')
if r then
return tonumber(r, 16), tonumber(g, 16) or 0, tonumber(b, 16) or 0, tonumber(a, 16) or 0
end
end
local alpha_from_style
alpha_from_style = function(scolor)
return ass_alpha(select(4, extract_color(scolor)))
end
local color_from_style
color_from_style = function(scolor)
local r, g, b = extract_color(scolor)
return ass_color(r or 0, g or 0, b or 0)
end
local HSV_to_RGB
HSV_to_RGB = function(H, S, V)
local r, g, b = 0, 0, 0
if S == 0 then
r = self:clamp(V * 255, 0, 255)
g = r
b = r
else
H = math.abs(H) % 360
local Hi = math.floor(H / 60)
local f = H / 60.0 - Hi
local p = V * (1 - S)
local q = V * (1 - f * S)
local t = V * (1 - (1 - f) * S)
if Hi == 0 then
r = V * 255.0
g = t * 255.0
b = p * 255.0
elseif Hi == 1 then
r = q * 255.0
g = V * 255.0
b = p * 255.0
elseif Hi == 2 then
r = p * 255.0
g = V * 255.0
b = t * 255.0
elseif Hi == 3 then
r = p * 255.0
g = q * 255.0
b = V * 255.0
elseif Hi == 4 then
r = t * 255.0
g = p * 255.0
b = V * 255.0
elseif Hi == 5 then
r = V * 255.0
g = p * 255.0
b = q * 255.0
else
error("math.floor(H % 360 / 60) should be [0, 6), is " .. tostring(Hi) .. "?")
end
end
return r, g, b
end
local HSL_to_RGB
HSL_to_RGB = function(H, S, L)
local r, g, b
H = math.abs(H) % 360
S = clamp(S, 0, 1)
L = clamp(L, 0, 1)
if S == 0 then
r = L
g = L
b = L
else
local Q
if L < 0.5 then
Q = L * (1.0 + S)
else
Q = L + S - (L * S)
end
local P = 2.0 * L - Q
local Hk = H / 360
local Tr, Tg, Tb
if Hk < 1 / 3 then
Tr = Hk + 1 / 3
Tg = Hk
Tb = Hk + 2 / 3
elseif Hk > 2 / 3 then
Tr = Hk - 2 / 3
Tg = Hk
Tb = Hk - 1 / 3
else
Tr = Hk + 1 / 3
Tg = Hk
Tb = Hk - 1 / 3
end
local get_component
get_component = function(T)
if T < 1 / 6 then
return P + ((Q - P) * 6.0 * T)
elseif 1 / 6 <= T and T < 1 / 2 then
return Q
elseif 1 / 2 <= T and T < 2 / 3 then
return P + ((Q - P) * (2 / 3 - T) * 6.0)
else
return P
end
end
r = get_component(Tr)
g = get_component(Tg)
b = get_component(Tb)
end
return math.floor(r * 255 + 0.5), math.floor(g * 255 + 0.5), math.floor(b * 255 + 0.5)
end
local trim
trim = function(s)
return s:gsub('^%s*(.-)%s*$', '%1')
end
local headtail
headtail = function(s)
local a, b, head, tail = s:find('(.-)%s+(.*)')
if a then
return head, tail
else
return s, ''
end
end
local words
words = function(s)
return function()
if s == '' then
return
end
local head, tail = headtail(s)
s = tail
return head
end
end
local clamp
clamp = function(val, min, max)
if val < min then
return min
elseif val > max then
return max
else
return val
end
end
local interpolate
interpolate = function(pct, min, max)
if pct <= 0 then
return min
elseif pct >= 1 then
return max
else
return pct * (max - min) + min
end
end
local interpolate_color
interpolate_color = function(pct, first, last)
local r1, g1, b1 = extract_color(first)
local r2, g2, b2 = extract_color(last)
local r, g, b = interpolate(pct, r1, r2), interpolate(pct, g1, g2), interpolate(pct, b1, b2)
return ass_color(r, g, b)
end
local interpolate_alpha
interpolate_alpha = function(pct, first, last)
return ass_alpha(interpolate(pct, select(4, extract_color(first)), select(4, extract_color(last))))
end
return {
copy = copy,
deep_copy = deep_copy,
ass_color = ass_color,
ass_alpha = ass_alpha,
ass_style_color = ass_style_color,
extract_color = extract_color,
alpha_from_style = alpha_from_style,
color_from_style = color_from_style,
HSV_to_RGB = HSV_to_RGB,
HSL_to_RGB = HSL_to_RGB,
trim = trim,
headtail = headtail,
words = words,
clamp = clamp,
interpolate = interpolate,
interpolate_color = interpolate_color,
interpolate_alpha = interpolate_alpha
} }
return utils

View File

@ -13,199 +13,203 @@
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
utils = sformat = string.format
-- Make a shallow copy of a table
copy: (tbl) -> {k, v for k, v in pairs tbl}
-- Make a deep copy of a table -- Make a shallow copy of a table
-- Retains equality of table references inside the copy and handles self-referencing structures copy = (tbl) -> {k, v for k, v in pairs tbl}
deep_copy: (tbl) ->
seen = {}
copy = (val) ->
return val if type(tbl) != 'table'
return seen[val] if seen[tbl]
seen[val] = tbl
{k, copy(v) for k, v in pairs val}
copy tbl
-- Generates ASS hexadecimal string from R, G, B integer components, in &HBBGGRR& format -- Make a deep copy of a table
ass_color: (r, g, b) -> string.format "&H%02X%02X%02X&", b, g, r -- Retains equality of table references inside the copy and handles self-referencing structures
-- Format an alpha-string for \Xa style overrides deep_copy = (tbl) ->
ass_alpha: (a) -> string.format "&H%02X&", a seen = {}
-- Format an ABGR string for use in style definitions (these don't end with & either) copy = (val) ->
ass_style_color: (r, g, b, a) -> string.format "&H%02X%02X%02X%02X", a, b, g, r return val if type(tbl) != 'table'
return seen[val] if seen[tbl]
seen[val] = tbl
{k, copy(v) for k, v in pairs val}
copy tbl
-- Extract colour components of an ASS colour -- Generates ASS hexadecimal string from R, G, B integer components, in &HBBGGRR& format
extract_color: (s) -> ass_color = (r, g, b) -> sformat "&H%02X%02X%02X&", b, g, r
local a, b, g, r -- Format an alpha-string for \Xa style overrides
ass_alpha = (a) -> sformat "&H%02X&", a
-- Format an ABGR string for use in style definitions (these don't end with & either)
ass_style_color = (r, g, b, a) -> sformat "&H%02X%02X%02X%02X", a, b, g, r
-- Try a style first -- Extract colour components of an ASS colour
a, b, g, r = s\match '&H(%x%x)(%x%x)(%x%x)(%x%x)' extract_color = (s) ->
if a then local a, b, g, r
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16)
-- Then a colour override -- Try a style first
b, g, r = s\match '&H(%x%x)(%x%x)(%x%x)&' a, b, g, r = s\match '&H(%x%x)(%x%x)(%x%x)(%x%x)'
if b then if a then
return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), 0 return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16)
-- Then an alpha override -- Then a colour override
a = s\match '&H(%x%x)&' b, g, r = s\match '&H(%x%x)(%x%x)(%x%x)&'
if a then if b then
return 0, 0, 0, tonumber(a, 16) return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), 0
-- Ok how about HTML format then? -- Then an alpha override
r, g, b, a = s\match '#(%x%x)(%x?%x?)(%x?%x?)(%x?%x?)' a = s\match '&H(%x%x)&'
if r then if a then
return tonumber(r, 16), tonumber(g, 16) or 0, tonumber(b, 16) or 0, tonumber(a, 16) or 0 return 0, 0, 0, tonumber(a, 16)
-- Create an alpha override code from a style definition colour code -- Ok how about HTML format then?
alpha_from_style: (scolor) -> ass_alpha select 4, extract_color scolor r, g, b, a = s\match '#(%x%x)(%x?%x?)(%x?%x?)(%x?%x?)'
if r then
return tonumber(r, 16), tonumber(g, 16) or 0, tonumber(b, 16) or 0, tonumber(a, 16) or 0
-- Create an colour override code from a style definition colour code -- Create an alpha override code from a style definition colour code
color_from_style: (scolor) -> alpha_from_style = (scolor) -> ass_alpha select 4, extract_color scolor
r, g, b = extract_color scolor
ass_color r or 0, g or 0, b or 0
-- Converts HSV (Hue, Saturation, Value) to RGB -- Create an colour override code from a style definition colour code
HSV_to_RGB: (H, S, V) -> color_from_style = (scolor) ->
r, g, b = 0, 0, 0 r, g, b = extract_color scolor
ass_color r or 0, g or 0, b or 0
-- Saturation is zero, make grey -- Converts HSV (Hue, Saturation, Value) to RGB
if S == 0 HSV_to_RGB = (H, S, V) ->
r = @clamp(V*255, 0, 255) r, g, b = 0, 0, 0
g = r
b = r
-- Else, calculate color -- Saturation is zero, make grey
if S == 0
r = @clamp(V*255, 0, 255)
g = r
b = r
-- Else, calculate color
else
-- Calculate subvalues
H = math.abs(H) % 360 -- Put H in range [0, 360)
Hi = math.floor(H/60)
f = H/60.0 - Hi
p = V*(1-S)
q = V*(1-f*S)
t = V*(1-(1-f)*S)
-- Do math based on hue index
if Hi == 0
r = V*255.0
g = t*255.0
b = p*255.0
elseif Hi == 1
r = q*255.0
g = V*255.0
b = p*255.0
elseif Hi == 2
r = p*255.0
g = V*255.0
b = t*255.0
elseif Hi == 3
r = p*255.0
g = q*255.0
b = V*255.0
elseif Hi == 4
r = t*255.0
g = p*255.0
b = V*255.0
elseif Hi == 5
r = V*255.0
g = p*255.0
b = q*255.0
else else
-- Calculate subvalues error "math.floor(H % 360 / 60) should be [0, 6), is #{Hi}?"
H = math.abs(H) % 360 -- Put H in range [0, 360)
Hi = math.floor(H/60)
f = H/60.0 - Hi
p = V*(1-S)
q = V*(1-f*S)
t = V*(1-(1-f)*S)
-- Do math based on hue index return r, g, b
if Hi == 0
r = V*255.0
g = t*255.0
b = p*255.0
elseif Hi == 1
r = q*255.0
g = V*255.0
b = p*255.0
elseif Hi == 2
r = p*255.0
g = V*255.0
b = t*255.0
elseif Hi == 3
r = p*255.0
g = q*255.0
b = V*255.0
elseif Hi == 4
r = t*255.0
g = p*255.0
b = V*255.0
elseif Hi == 5
r = V*255.0
g = p*255.0
b = q*255.0
else
error "math.floor(H % 360 / 60) should be [0, 6), is #{Hi}?"
return r, g, b -- Convert HSL (Hue, Saturation, Luminance) to RGB
-- Contributed by Gundamn
HSL_to_RGB = (H, S, L) ->
local r, g, b
-- Convert HSL (Hue, Saturation, Luminance) to RGB -- Make sure input is in range
-- Contributed by Gundamn H = math.abs(H) % 360
HSL_to_RGB: (H, S, L) -> S = clamp(S, 0, 1)
local r, g, b L = clamp(L, 0, 1)
-- Make sure input is in range if S == 0 -- Simple case if saturation is 0, all grey
H = math.abs(H) % 360 r = L
S = clamp(S, 0, 1) g = L
L = clamp(L, 0, 1) b = L
else
if S == 0 -- Simple case if saturation is 0, all grey -- More common case, saturated colour
r = L Q = if L < 0.5
g = L L * (1.0 + S)
b = L
else else
-- More common case, saturated colour L + S - (L * S)
Q = if L < 0.5
L * (1.0 + S) P = 2.0 * L - Q
Hk = H / 360
local Tr, Tg, Tb
if Hk < 1/3
Tr = Hk + 1/3
Tg = Hk
Tb = Hk + 2/3
elseif Hk > 2/3
Tr = Hk - 2/3
Tg = Hk
Tb = Hk - 1/3
else
Tr = Hk + 1/3
Tg = Hk
Tb = Hk - 1/3
get_component = (T) ->
if T < 1/6
P + ((Q - P) * 6.0 * T)
elseif 1/6 <= T and T < 1/2
Q
elseif 1/2 <= T and T < 2/3
P + ((Q - P) * (2/3 - T) * 6.0)
else else
L + S - (L * S) P
P = 2.0 * L - Q r = get_component(Tr)
g = get_component(Tg)
b = get_component(Tb)
Hk = H / 360 return math.floor(r*255+0.5), math.floor(g*255+0.5), math.floor(b*255+0.5)
local Tr, Tg, Tb -- Removes spaces at the start and end of string
if Hk < 1/3 trim = (s) -> s\gsub '^%s*(.-)%s*$', '%1'
Tr = Hk + 1/3
Tg = Hk
Tb = Hk + 2/3
elseif Hk > 2/3
Tr = Hk - 2/3
Tg = Hk
Tb = Hk - 1/3
else
Tr = Hk + 1/3
Tg = Hk
Tb = Hk - 1/3
get_component = (T) -> -- Get the 'head' and 'tail' of a string, treating it as a sequence of words separated by one or more space-characters
if T < 1/6 headtail = (s) ->
P + ((Q - P) * 6.0 * T) a, b, head, tail = s\find '(.-)%s+(.*)'
elseif 1/6 <= T and T < 1/2 if a then head, tail else s, ''
Q
elseif 1/2 <= T and T < 2/3
P + ((Q - P) * (2/3 - T) * 6.0)
else
P
r = get_component(Tr) -- Iterator function for headtail
g = get_component(Tg) words = (s) -> ->
b = get_component(Tb) return if s == ''
head, tail = headtail s
s = tail
head
return math.floor(r*255+0.5), math.floor(g*255+0.5), math.floor(b*255+0.5) -- Clamp a number value to a range
clamp = (val, min, max) ->
if val < min then min elseif val > max then max else val
-- Removes spaces at the start and end of string -- Interpolate between two numbers
trim: (s) -> s\gsub '^%s*(.-)%s*$', '%1' interpolate = (pct, min, max) ->
if pct <= 0 then min elseif pct >= 1 then max else pct * (max - min) + min
-- Get the 'head' and 'tail' of a string, treating it as a sequence of words separated by one or more space-characters -- Interpolate between two colour values, given in either style definition or style override format
headtail: (s) -> -- Return in style override format
a, b, head, tail = s\find '(.-)%s+(.*)' interpolate_color = (pct, first, last) ->
if a then head, tail else s, '' r1, g1, b1 = extract_color first
r2, g2, b2 = extract_color last
r, g, b = interpolate(pct, r1, r2), interpolate(pct, g1, g2), interpolate(pct, b1, b2)
ass_color r, g, b
-- Iterator function for headtail -- Interpolate between two alpha values, given either in style override or as part as a style definition colour
words: (s) -> -> -- Return in style override format
return if s == '' interpolate_alpha = (pct, first, last) ->
head, tail = string.headtail s ass_alpha interpolate pct, select(4, extract_color first), select(4, extract_color last)
s = tail
head
-- Clamp a number value to a range { :copy, :deep_copy, :ass_color, :ass_alpha, :ass_style_color,
clamp: (val, min, max) -> :extract_color, :alpha_from_style, :color_from_style, :HSV_to_RGB,
if val < min then min elseif val > max then max else val :HSL_to_RGB, :trim, :headtail, :words, :clamp, :interpolate,
:interpolate_color, :interpolate_alpha }
-- Interpolate between two numbers
interpolate: (pct, min, max) ->
if pct <= 0 then min elseif pct >= 1 then max else pct * (max - min) + min
-- Interpolate between two colour values, given in either style definition or style override format
-- Return in style override format
interpolate_color: (pct, first, last) ->
r1, g1, b1 = extract_color first
r2, g2, b2 = extract_color last
r, g, b = interpolate(pct, r1, r2), interpolate(pct, g1, g2), interpolate(pct, b1, b2)
ass_color r, g, b
-- Interpolate between two alpha values, given either in style override or as part as a style definition colour
-- Return in style override format
interpolate_alpha: (pct, first, last) ->
ass_alpha interpolate pct, select(4, extract_color first), select(4, extract_color last)
utils