From 9e423fea1a4434588c0788f16be8ad177e18c988 Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Sun, 18 Jun 2017 11:11:01 +0200 Subject: [PATCH] Initial Commit of Colors. --- colors.lua | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++ init.lua | 1 + 2 files changed, 148 insertions(+) create mode 100644 colors.lua create mode 100644 init.lua diff --git a/colors.lua b/colors.lua new file mode 100644 index 0000000..5eca7a1 --- /dev/null +++ b/colors.lua @@ -0,0 +1,147 @@ +--[[ + This is a collection of functions for performing color operations, + designed to work with the LÖVE game engine. + + See `README_COLOR_TOOLS.md` for full documentation. + + LICENSE is BEER-WARE. +]] + +local colors = {} + +-------------------------------------------------------------------------------- +-- Conversion + +colors.rgb_to_hsl = function (color) + -- Error check + assert(type(color) == 'table' and type(color[1]) == 'number' and type(color[2]) == 'number' and type(color[3]) == 'number') + + -- Do stuff + local r = (color[1] == 255 and 1 or color[1]/256) + local g = (color[2] == 255 and 1 or color[2]/256) + local b = (color[3] == 255 and 1 or color[3]/256) + + local max, min = math.max(r, g, b), math.min(r, g, b) + local h, s, l = (max+min)/2, (max+min)/2, (max+min)/2 + if min == max then + return {0, 0, l} + end + + local d = max - min + s = l > 0.5 and d / (2 - max - min) or d / (max + min) + if max == r then + h = ((g - b) / d + (g < b and 6 or 0)) / 6 + elseif max == g then + h = ((b - r) / d + 2) / 6 + elseif max == b then + h = ((r - g) / d + 4) / 6 + end + + return {h, s, l} +end + +local function hue_to_rgb (p, q, t) + assert(type(p) == 'number') + assert(type(q) == 'number') + assert(type(t) == 'number') + + if t < 0 then + t = t + 1 + end + if t > 1 then + t = t - 1 + end + if t < 1/6 then + return p + (q - p) * 6 * t + elseif t < 1/2 then + return q + elseif t < 2/3 then + return p + (q - p) * 6 * (2/3 - t) + end + return p +end + +colors.hsl_to_rgb = function (color) + -- Error check + assert(type(color) == 'table' and type(color[1]) == 'number' and type(color[2]) == 'number' and type(color[3]) == 'number') + + -- Do stuff + local h, s, l = color[1], color[2], color[3] + local r, g, b + if s == 0 then + r, g, b = l, l, l + else + local q = l < 0.5 and l * (1+s) or l+s - l*s + local p = 2 * l - q + r, g, b = hue_to_rgb(p,q,h+1/3), hue_to_rgb(p,q,h), hue_to_rgb(p,q,h-1/3) + end + r, g, b = math.floor(math.min(255,r*256)+0.5), math.floor(math.min(255,g*256)+0.5), math.floor(math.min(255,b*256)+0.5) + return { r, g, b } +end + +-------------------------------------------------------------------------------- +-- Interpolation + +colors.interpolate_rgb = function (c1, c2, t) + return { c1[1]+(c2[1]-c1[1])*t, c1[2]+(c2[2]-c1[2])*t, c1[3]+(c2[3]-c1[3])*t } +end + +local function angle_delta (a1, a2) + assert(type(a1) == 'number') + assert(type(a2) == 'number') + local r1, r2 = (a1-a2)%1, (a2-a1)%1 + return r1 < r2 and -r1 or r2 +end + +colors.interpolate_hsl = function (c1, c2, t) + -- Error handling + assert(type(c1) == 'table' and type(c1[1]) == 'number' and type(c1[2]) == 'number' and type(c1[3]) == 'number') + assert(type(c2) == 'table' and type(c2[1]) == 'number' and type(c2[2]) == 'number' and type(c2[3]) == 'number') + assert(type(t) == 'number') + -- Do stuff + local h = c1[1] + angle_delta(c1[1], c2[1]) * t + local s = c1[2] + (c2[2] - c1[2]) * t + local l = c1[3] + (c2[3] - c1[3]) * t + return { h, s, l } +end + +colors.interpolate_rgb_by_way_of_hsl = function (c1, c2, t) + -- Error handling + assert(type(c1) == 'table' and type(c1[1]) == 'number' and type(c1[2]) == 'number' and type(c1[3]) == 'number') + assert(type(c2) == 'table' and type(c2[1]) == 'number' and type(c2[2]) == 'number' and type(c2[3]) == 'number') + assert(type(t) == 'number') + -- Do stuff + local c1_hsl = colors.rgb_to_hsl(c1) + local c2_hsl = colors.rgb_to_hsl(c2) + local c3_hsl = colors.interpolate_hsl(c1_hsl, c2_hsl, t) + return colors.hsl_to_rgb(c3_hsl) +end + +-------------------------------------------------------------------------------- +-- Inversion + +colors.invert_rgb = function (color) + assert(type(color) == 'table' and type(color[1]) == 'number' and type(color[2]) == 'number' and type(color[3]) == 'number') + return { 255 - color[1], 255 - color[2], 255 - color[3] } +end + +-------------------------------------------------------------------------------- +-- Parsing + +colors.parse_rgb = function (str) + -- Error handling + assert(type(str) == 'string') + -- Do stuff + local r, g, b + local o = (str:sub(1,1) == '#') and 1 or 0 -- Offset + if #str == 3 or #str == 4 then + r, g, b = str:sub(o+1,o+1):rep(2), str:sub(o+2,o+2):rep(2), str:sub(o+3,o+3):rep(2) + else + r, g, b = str:sub(o+1,o+2), str:sub(o+3,o+4), str:sub(o+5,o+6) + end + return {tonumber('0x'..r), tonumber('0x'..g), tonumber('0x'..b)} +end + +-------------------------------------------------------------------------------- + +return colors diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..86fc208 --- /dev/null +++ b/init.lua @@ -0,0 +1 @@ +return require 'colors.colors'