color.lua 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. --- Color utilities
  2. -- @module color
  3. local modules = (...):gsub('%.[^%.]+$', '') .. "."
  4. local utils = require(modules .. "utils")
  5. local color = {}
  6. local color_mt = {}
  7. local function new(r, g, b, a)
  8. local c = { r, g, b, a }
  9. c._c = c
  10. return setmetatable(c, color)
  11. end
  12. -- HSV utilities (adapted from http://www.cs.rit.edu/~ncs/color/t_convert.html)
  13. -- hsv_to_color(hsv)
  14. -- Converts a set of HSV values to a color. hsv is a table.
  15. -- See also: hsv(h, s, v)
  16. local function hsv_to_color(hsv)
  17. local i
  18. local f, q, p, t
  19. local h, s, v
  20. local a = hsv[4] or 255
  21. s = hsv[2]
  22. v = hsv[3]
  23. if s == 0 then
  24. return new(v, v, v, a)
  25. end
  26. h = hsv[1] / 60
  27. i = math.floor(h)
  28. f = h - i
  29. p = v * (1-s)
  30. q = v * (1-s*f)
  31. t = v * (1-s*(1-f))
  32. if i == 0 then return new(v, t, p, a)
  33. elseif i == 1 then return new(q, v, p, a)
  34. elseif i == 2 then return new(p, v, t, a)
  35. elseif i == 3 then return new(p, q, v, a)
  36. elseif i == 4 then return new(t, p, v, a)
  37. else return new(v, p, q, a)
  38. end
  39. end
  40. -- color_to_hsv(c)
  41. -- Takes in a normal color and returns a table with the HSV values.
  42. local function color_to_hsv(c)
  43. local r = c[1]
  44. local g = c[2]
  45. local b = c[3]
  46. local a = c[4] or 255
  47. local h, s, v
  48. local min = math.min(r, g, b)
  49. local max = math.max(r, g, b)
  50. v = max
  51. local delta = max - min
  52. -- black, nothing else is really possible here.
  53. if min == 0 and max == 0 then
  54. return { 0, 0, 0, a }
  55. end
  56. if max ~= 0 then
  57. s = delta / max
  58. else
  59. -- r = g = b = 0 s = 0, v is undefined
  60. s = 0
  61. h = -1
  62. return { h, s, v, 255 }
  63. end
  64. if r == max then
  65. h = ( g - b ) / delta -- yellow/magenta
  66. elseif g == max then
  67. h = 2 + ( b - r ) / delta -- cyan/yellow
  68. else
  69. h = 4 + ( r - g ) / delta -- magenta/cyan
  70. end
  71. h = h * 60 -- degrees
  72. if h < 0 then
  73. h = h + 360
  74. end
  75. return { h, s, v, a }
  76. end
  77. function color.new(r, g, b, a)
  78. -- number, number, number, number
  79. if r and g and b and a then
  80. assert(type(r) == "number", "new: Wrong argument type for r (<number> expected)")
  81. assert(type(g) == "number", "new: Wrong argument type for g (<number> expected)")
  82. assert(type(b) == "number", "new: Wrong argument type for b (<number> expected)")
  83. assert(type(a) == "number", "new: Wrong argument type for a (<number> expected)")
  84. return new(r, g, b, a)
  85. -- {r, g, b, a}
  86. elseif type(r) == "table" then
  87. local rr, gg, bb, aa = r[1], r[2], r[3], r[4]
  88. assert(type(rr) == "number", "new: Wrong argument type for r (<number> expected)")
  89. assert(type(gg) == "number", "new: Wrong argument type for g (<number> expected)")
  90. assert(type(bb) == "number", "new: Wrong argument type for b (<number> expected)")
  91. assert(type(aa) == "number", "new: Wrong argument type for a (<number> expected)")
  92. return new(rr, gg, bb, aa)
  93. end
  94. new(0, 0, 0, 0)
  95. end
  96. function color.from_hsv(h, s, v)
  97. return hsv_to_color { h, s, v, 255 }
  98. end
  99. function color.from_hsva(h, s, v, a)
  100. return hsv_to_color { h, s, v, a }
  101. end
  102. function color.invert(c)
  103. return new(255 - c[1], 255 - c[2], 255 - c[3], c[4])
  104. end
  105. function color.lighten(c, v)
  106. return new(
  107. utils.clamp(c[1] + v * 255, 0, 255),
  108. utils.clamp(c[2] + v * 255, 0, 255),
  109. utils.clamp(c[3] + v * 255, 0, 255),
  110. c[4]
  111. )
  112. end
  113. function color.lerp(a, b, s)
  114. return a + s * (b - a)
  115. end
  116. function color.darken(c, v)
  117. return new(
  118. utils.clamp(c[1] - v * 255, 0, 255),
  119. utils.clamp(c[2] - v * 255, 0, 255),
  120. utils.clamp(c[3] - v * 255, 0, 255),
  121. c[4]
  122. )
  123. end
  124. function color.multiply(c, v)
  125. local t = color.new()
  126. for i = 1, 3 do
  127. t[i] = c[i] * v
  128. end
  129. t[4] = c[4]
  130. return t
  131. end
  132. -- directly set alpha channel
  133. function color.alpha(c, v)
  134. local t = color.new()
  135. for i = 1, 3 do
  136. t[i] = c[i]
  137. end
  138. t[4] = v * 255
  139. return t
  140. end
  141. function color.opacity(c, v)
  142. local t = color.new()
  143. for i = 1, 3 do
  144. t[i] = c[i]
  145. end
  146. t[4] = c[4] * v
  147. return t
  148. end
  149. function color.hue(col, hue)
  150. local c = color_to_hsv(col)
  151. c[1] = (hue + 360) % 360
  152. return hsv_to_color(c)
  153. end
  154. function color.saturation(col, percent)
  155. local c = color_to_hsv(col)
  156. c[2] = utils.clamp(percent, 0, 1)
  157. return hsv_to_color(c)
  158. end
  159. function color.value(col, percent)
  160. local c = color_to_hsv(col)
  161. c[3] = utils.clamp(percent, 0, 1)
  162. return hsv_to_color(c)
  163. end
  164. -- http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
  165. function color.gamma_to_linear(r, g, b, a)
  166. local function convert(c)
  167. if c > 1.0 then
  168. return 1.0
  169. elseif c < 0.0 then
  170. return 0.0
  171. elseif c <= 0.04045 then
  172. return c / 12.92
  173. else
  174. return math.pow((c + 0.055) / 1.055, 2.4)
  175. end
  176. end
  177. if type(r) == "table" then
  178. local c = {}
  179. for i = 1, 3 do
  180. c[i] = convert(r[i] / 255) * 255
  181. end
  182. c[4] = convert(r[4] / 255) * 255
  183. return c
  184. else
  185. return convert(r / 255) * 255, convert(g / 255) * 255, convert(b / 255) * 255, a or 255
  186. end
  187. end
  188. -- http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29
  189. function color.linear_to_gamma(r, g, b, a)
  190. local function convert(c)
  191. if c > 1.0 then
  192. return 1.0
  193. elseif c < 0.0 then
  194. return 0.0
  195. elseif c < 0.0031308 then
  196. return c * 12.92
  197. else
  198. return 1.055 * math.pow(c, 0.41666) - 0.055
  199. end
  200. end
  201. if type(r) == "table" then
  202. local c = {}
  203. for i = 1, 3 do
  204. c[i] = convert(r[i] / 255) * 255
  205. end
  206. c[4] = convert(r[4] / 255) * 255
  207. return c
  208. else
  209. return convert(r / 255) * 255, convert(g / 255) * 255, convert(b / 255) * 255, a or 255
  210. end
  211. end
  212. function color.is_color(a)
  213. if type(a) ~= "table" then
  214. return false
  215. end
  216. for i = 1, 4 do
  217. if type(a[i]) ~= "number" then
  218. return false
  219. end
  220. end
  221. return true
  222. end
  223. function color.to_string(a)
  224. return string.format("[ %3.0f, %3.0f, %3.0f, %3.0f ]", a[1], a[2], a[3], a[4])
  225. end
  226. function color_mt.__index(t, k)
  227. if type(t) == "cdata" then
  228. if type(k) == "number" then
  229. return t._c[k-1]
  230. end
  231. end
  232. return rawget(color, k)
  233. end
  234. function color_mt.__newindex(t, k, v)
  235. if type(t) == "cdata" then
  236. if type(k) == "number" then
  237. t._c[k-1] = v
  238. end
  239. end
  240. end
  241. color_mt.__tostring = color.to_string
  242. function color_mt.__call(_, r, g, b, a)
  243. return color.new(r, g, b, a)
  244. end
  245. function color_mt.__add(a, b)
  246. return new(a[1] + b[1], a[2] + b[2], a[3] + b[3], a[4] + b[4])
  247. end
  248. function color_mt.__sub(a, b)
  249. return new(a[1] - b[1], a[2] - b[2], a[3] - b[3], a[4] - b[4])
  250. end
  251. function color_mt.__mul(a, b)
  252. if type(a) == "number" then
  253. return new(a * b[1], a * b[2], a * b[3], a * b[4])
  254. elseif type(b) == "number" then
  255. return new(b * a[1], b * a[2], b * a[3], b * a[4])
  256. else
  257. return new(a[1] * b[1], a[2] * b[2], a[3] * b[3], a[4] * b[4])
  258. end
  259. end
  260. return setmetatable({}, color_mt)