Updated color module, etc.

This commit is contained in:
karai17 2016-07-20 22:17:25 -03:00
parent a57673dcaf
commit 2950352ac8
7 changed files with 208 additions and 140 deletions

View File

@ -1,102 +1,15 @@
--- Color utilities
-- @module color
local current_folder = (...):gsub('%.[^%.]+$', '') .. "."
local utils = require(current_folder .. "utils")
local color = {}
local modules = (...):gsub('%.[^%.]+$', '') .. "."
local utils = require(modules .. "utils")
local color = {}
local function new(r, g, b, a)
return setmetatable({
r, g, b, a
-- utils.clamp(r or 0, 0, 255),
-- utils.clamp(g or 0, 0, 255),
-- utils.clamp(b or 0, 0, 255),
-- utils.clamp(a or 255, 0, 255)
}, color)
end
color.__index = color
color.__call = function(_, ...) return new(...) end
function color.invert(c)
return new(255 - c[1], 255 - c[2], 255 - c[3], c[4])
end
function color.lighten(c, v)
return new(
utils.clamp(c[1] + v * 255, 0, 255),
utils.clamp(c[2] + v * 255, 0, 255),
utils.clamp(c[3] + v * 255, 0, 255),
c[4]
)
end
function color.__tostring(a)
return string.format("[ %3.0f, %3.0f, %3.0f, %3.0f ]", a[1], a[2], a[3], a[4])
end
function color.__add(a, b)
return new(a[1] + b[1], a[2] + b[2], a[3] + b[3], a[4] + b[4])
end
function color.__sub(a, b)
return new(a[1] - b[1], a[2] - b[2], a[3] - b[3], a[4] - b[4])
end
function color.__mul(a, b)
if type(a) == "number" then
return new(a * b[1], a * b[2], a * b[3], a * b[4])
elseif type(b) == "number" then
return new(b * a[1], b * a[2], b * a[3], b * a[4])
else
return new(a[1] * b[1], a[2] * b[2], a[3] * b[3], a[4] * b[4])
end
end
function color.lerp(a, b, s)
return a + s * (b - a)
end
function color.darken(c, v)
return new(
utils.clamp(c[1] - v * 255, 0, 255),
utils.clamp(c[2] - v * 255, 0, 255),
utils.clamp(c[3] - v * 255, 0, 255),
c[4]
)
end
function color.mul(c, v)
local t = {}
for i=1,3 do
t[i] = c[i] * v
end
t[4] = c[4]
setmetatable(t, color)
return t
end
-- directly set alpha channel
function color.alpha(c, v)
local t = {}
for i=1,3 do
t[i] = c[i]
end
t[4] = v * 255
setmetatable(t, color)
return t
end
function color.opacity(c, v)
local t = {}
for i=1,3 do
t[i] = c[i]
end
t[4] = c[4] * v
setmetatable(t, color)
return t
return setmetatable({ r, g, b, a }, color)
end
-- HSV utilities (adapted from http://www.cs.rit.edu/~ncs/color/t_convert.html)
-- hsv_to_color(hsv)
-- Converts a set of HSV values to a color. hsv is a table.
-- See also: hsv(h, s, v)
@ -121,7 +34,7 @@ local function hsv_to_color(hsv)
q = v * (1-s*f)
t = v * (1-s*(1-f))
if i == 0 then return new(v, t, p, a)
if i == 0 then return new(v, t, p, a)
elseif i == 1 then return new(q, v, p, a)
elseif i == 2 then return new(p, v, t, a)
elseif i == 3 then return new(p, q, v, a)
@ -130,14 +43,6 @@ local function hsv_to_color(hsv)
end
end
function color.from_hsv(h, s, v)
return hsv_to_color { h, s, v, 255 }
end
function color.from_hsva(h, s, v, a)
return hsv_to_color { h, s, v, a }
end
-- color_to_hsv(c)
-- Takes in a normal color and returns a table with the HSV values.
local function color_to_hsv(c)
@ -187,9 +92,99 @@ local function color_to_hsv(c)
return { h, s, v, a }
end
function color.hue(color, newHue)
function color.new(r, g, b, a)
-- number, number, number, number
if r and g and b and a then
assert(type(r) == "number", "new: Wrong argument type for r (<number> expected)")
assert(type(g) == "number", "new: Wrong argument type for g (<number> expected)")
assert(type(b) == "number", "new: Wrong argument type for b (<number> expected)")
assert(type(a) == "number", "new: Wrong argument type for a (<number> expected)")
return new(r, g, b, a)
end
-- {x, y, z, w}
elseif type(x) == "table" then
local r, g, b, a = r[1], r[2], r[3], r[4]
assert(type(r) == "number", "new: Wrong argument type for r (<number> expected)")
assert(type(g) == "number", "new: Wrong argument type for g (<number> expected)")
assert(type(b) == "number", "new: Wrong argument type for b (<number> expected)")
assert(type(a) == "number", "new: Wrong argument type for a (<number> expected)")
return new(r, g, b, a)
end
new(0, 0, 0, 0)
end
function color.from_hsv(h, s, v)
return hsv_to_color { h, s, v, 255 }
end
function color.from_hsva(h, s, v, a)
return hsv_to_color { h, s, v, a }
end
function color.invert(c)
return new(255 - c[1], 255 - c[2], 255 - c[3], c[4])
end
function color.lighten(c, v)
return new(
utils.clamp(c[1] + v * 255, 0, 255),
utils.clamp(c[2] + v * 255, 0, 255),
utils.clamp(c[3] + v * 255, 0, 255),
c[4]
)
end
function color.lerp(a, b, s)
return a + s * (b - a)
end
function color.darken(c, v)
return new(
utils.clamp(c[1] - v * 255, 0, 255),
utils.clamp(c[2] - v * 255, 0, 255),
utils.clamp(c[3] - v * 255, 0, 255),
c[4]
)
end
function color.multiply(c, v)
local t = color.new()
for i = 1, 3 do
t[i] = c[i] * v
end
t[4] = c[4]
return t
end
-- directly set alpha channel
function color.alpha(c, v)
local t = color.new()
for i = 1, 3 do
t[i] = c[i]
end
t[4] = v * 255
return t
end
function color.opacity(c, v)
local t = color.new()
for i = 1, 3 do
t[i] = c[i]
end
t[4] = c[4] * v
return t
end
function color.hue(color, hue)
local c = color_to_hsv(color)
c[1] = (newHue + 360) % 360
c[1] = (hue + 360) % 360
return hsv_to_color(c)
end
@ -218,11 +213,13 @@ function color.gamma_to_linear(r, g, b, a)
return math.pow((c + 0.055) / 1.055, 2.4)
end
end
if type(r) == "table" then
local c = {}
for i=1,3 do
for i = 1, 3 do
c[i] = convert(r[i] / 255) * 255
end
c[4] = convert(r[4] / 255) * 255
return c
else
@ -243,11 +240,13 @@ function color.linear_to_gamma(r, g, b, a)
return 1.055 * math.pow(c, 0.41666) - 0.055
end
end
if type(r) == "table" then
local c = {}
for i=1,3 do
for i = 1, 3 do
c[i] = convert(r[i] / 255) * 255
end
c[4] = convert(r[4] / 255) * 255
return c
else
@ -255,4 +254,34 @@ function color.linear_to_gamma(r, g, b, a)
end
end
return setmetatable({new = new}, color)
function color.to_string(a)
return string.format("[ %3.0f, %3.0f, %3.0f, %3.0f ]", a[1], a[2], a[3], a[4])
end
local color_mt = {}
color_mt.__index = color
color_mt.__tostring = color.to_string
function color_mt.__call(_, r, g, b, a)
return color.new(r, g, b, a)
end
function color_mt.__add(a, b)
return new(a[1] + b[1], a[2] + b[2], a[3] + b[3], a[4] + b[4])
end
function color_mt.__sub(a, b)
return new(a[1] - b[1], a[2] - b[2], a[3] - b[3], a[4] - b[4])
end
function color_mt.__mul(a, b)
if type(a) == "number" then
return new(a * b[1], a * b[2], a * b[3], a * b[4])
elseif type(b) == "number" then
return new(b * a[1], b * a[2], b * a[3], b * a[4])
else
return new(a[1] * b[1], a[2] * b[2], a[3] * b[3], a[4] * b[4])
end
end
return setmetatable({}, color_mt)

View File

@ -627,7 +627,7 @@ local mat4_mt = {}
mat4_mt.__index = mat4
mat4_mt.__tostring = mat4.to_string
function mat4_mt.__call(self, a)
function mat4_mt.__call(_, a)
return mat4.new(a)
end

View File

@ -5,21 +5,58 @@ local modules = (...):gsub('%.[^%.]+$', '') .. "."
local vec3 = require(modules .. "vec3")
local mesh = {}
function mesh.compute_normal(a, b, c)
-- vertices is an arbitrary list of vec3s
function mesh.average(vertices)
local out = vec3()
local ca = vec3.sub(vec3(), c, a)
local ba = vec3.sub(vec3(), b, a)
vec3.cross(out, ca, ba)
vec3.normalize(out, out)
for _, v in ipairs(vertices) do
out:add(out, v)
end
return out:div(out, #vertices)
end
-- triangle[1] is a vec3
-- triangle[2] is a vec3
-- triangle[3] is a vec3
function mesh.normal(triangle)
local ca = vec3():sub(triangle[3], triangle[1])
local ba = vec3():sub(triangle[2], triangle[1])
local out = vec3()
return out
:cross(ca, ba)
:normalize(out)
end
-- triangle[1] is a vec3
-- triangle[2] is a vec3
-- triangle[3] is a vec3
function mesh.plane_from_triangle(triangle)
local out = {}
local ca = vec3():sub(triangle[3], triangle[1])
local ba = vec3():sub(triangle[2], triangle[1])
out.origin = triangle[1]
out.normal = vec3()
:cross(ba, ca)
:normalize(out)
out.dot = -out.normal:dot(out.origin)
return out
end
function mesh.average(vertices)
local out = vec3(0, 0, 0)
for _, v in ipairs(vertices) do
vec3.add(out, out, v)
end
return vec3.div(out, out, #vertices)
-- plane.origin is a vec3
-- plane.normal is a vec3
-- direction is a vec3
function mesh.is_front_facing(plane, direction)
return plane.normal:dot(direction) <= 0
end
-- point is a vec3
-- plane.origin is a vec3
-- plane.normal is a vec3
-- plane.dot is a number
function mesh.signed_distance(point, plane)
dot = plane.dot or -plane.normal:dot(plane.origin)
return point:dot(plane.normal) + dot
end
return mesh

View File

@ -67,10 +67,9 @@ function quat.new(x, y, z, w)
assert(type(w) == "number", "new: Wrong argument type for w (<number> expected)")
return new(x, y, z, w)
else
return new(0, 0, 0, 1)
end
return new(0, 0, 0, 1)
end
--- Create a quaternion from an axis, angle pair.
@ -408,7 +407,7 @@ local quat_mt = {}
quat_mt.__index = quat
quat_mt.__tostring = quat.to_string
function quat_mt.__call(self, x, y, z, w)
function quat_mt.__call(_, x, y, z, w)
return new(x, y, z, w)
end

View File

@ -121,9 +121,9 @@ function utils.project_on(out, a, b)
(a.x * b.x + a.y * b.y + isvec3 and a.z * b.z or 0) /
(b.x * b.x + b.y * b.y + isvec3 and b.z * b.z or 0)
out.x = b.x * s
out.y = b.y * s
out.z = isvec3 and b.z * s or nil
out.x = b.x * s
out.y = b.y * s
out.z = isvec3 and b.z * s or nil
return out
end
@ -135,9 +135,9 @@ function utils.project_from(out, a, b)
(b.x * b.x + b.y * b.y + isvec3 and b.z * b.z or 0) /
(a.x * b.x + a.y * b.y + isvec3 and a.z * b.z or 0)
out.x = b.x * s
out.y = b.y * s
out.z = isvec3 and b.z * s or nil
out.x = b.x * s
out.y = b.y * s
out.z = isvec3 and b.z * s or nil
return out
end
@ -148,28 +148,31 @@ function utils.mirror_on(out, a, b)
local s =
(a.x * b.x + a.y * b.y + isvec3 and a.z * b.z or 0) /
(b.x * b.x + b.y * b.y + isvec3 and b.z * b.z or 0) * 2
out.x = b.x * s - a.x
out.y = b.y * s - a.y
out.z = isvec3 and b.z * s - a.z or nil
out.x = b.x * s - a.x
out.y = b.y * s - a.y
out.z = isvec3 and b.z * s - a.z or nil
return out
end
-- Originally from vec3
function utils.reflect(out, i, n)
vec3.mul(out, n, vec3.dot(n, i) * 2)
vec3.sub(out, i, out)
return out
:mul(n, n:dot(i) * 2)
:sub(i, out)
end
-- Originally from vec3
local tmp = vec3()
function utils.refract(out, i, n, ior)
local d = vec3.dot(n, i)
local d = n:dot(i)
local k = 1 - ior * ior * (1 - d * d)
if k >= 0 then
vec3.mul(out, i, ior)
vec3.mul(tmp, n, ior * d + sqrt(k))
vec3.sub(out, out, tmp)
tmp:mul(n, ior * d + sqrt(k))
out:mul(i, ior)
out:sub(out, tmp)
end
return out

View File

@ -260,7 +260,7 @@ local vec2_mt = {}
vec2_mt.__index = vec2
vec2_mt.__tostring = vec2.to_string
function vec2_mt.__call(self, x, y)
function vec2_mt.__call(_, x, y)
return vec2.new(x, y)
end

View File

@ -275,7 +275,7 @@ local vec3_mt = {}
vec3_mt.__index = vec3
vec3_mt.__tostring = vec3.to_string
function vec3_mt.__call(self, x, y, z)
function vec3_mt.__call(_, x, y, z)
return vec3.new(x, y, z)
end
@ -283,7 +283,7 @@ function vec3_mt.__unm(a)
return new(-a.x, -a.y, -a.z)
end
function vec3_mt.__eq(a,b)
function vec3_mt.__eq(a, b)
assert(vec3.is_vec3(a), "__eq: Wrong argument type for left hand operant. (<cpml.vec3> expected)")
assert(vec3.is_vec3(b), "__eq: Wrong argument type for right hand operant. (<cpml.vec3> expected)")
return a.x == b.x and a.y == b.y and a.z == b.z