• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excessive / cpml / 13079282556

07 May 2022 10:53PM UTC coverage: 57.717% (+43.7%) from 14.013%
13079282556

push

github

shakesoda
fix typo in mat4.mul

0 of 1 new or added line in 1 file covered. (0.0%)

527 existing lines in 19 files now uncovered.

4581 of 7937 relevant lines covered (57.72%)

52.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.57
/modules/color.lua
1
--- Color utilities
2
-- @module color
3

4
local modules  = (...):gsub('%.[^%.]+$', '') .. "."
1✔
5
local constants = require(modules .. "constants")
1✔
6
local utils    = require(modules .. "utils")
1✔
7
local precond  = require(modules .. "_private_precond")
1✔
8
local color    = {}
1✔
9
local color_mt = {}
1✔
10

11
local function new(r, g, b, a)
12
        local c = { r, g, b, a }
54✔
13
        c._c = c
54✔
14
        return setmetatable(c, color_mt)
54✔
15
end
16

17
-- HSV utilities (adapted from http://www.cs.rit.edu/~ncs/color/t_convert.html)
18
-- hsv_to_color(hsv)
19
-- Converts a set of HSV values to a color. hsv is a table.
20
-- See also: hsv(h, s, v)
21
local function hsv_to_color(hsv)
22
        local i
23
        local f, q, p, t
24
        local h, s, v
25
        local a = hsv[4] or 1
17✔
26
        s = hsv[2]
17✔
27
        v = hsv[3]
17✔
28

29
        if s == 0 then
17✔
30
                return new(v, v, v, a)
3✔
31
        end
32

33
        h = hsv[1] * 6 -- sector 0 to 5
14✔
34

35
        i = math.floor(h)
14✔
36
        f = h - i -- factorial part of h
14✔
37
        p = v * (1-s)
14✔
38
        q = v * (1-s*f)
14✔
39
        t = v * (1-s*(1-f))
14✔
40

41
        if     i == 0 then return new(v, t, p, a)
14✔
42
        elseif i == 1 then return new(q, v, p, a)
12✔
43
        elseif i == 2 then return new(p, v, t, a)
10✔
44
        elseif i == 3 then return new(p, q, v, a)
9✔
45
        elseif i == 4 then return new(t, p, v, a)
6✔
46
        else               return new(v, p, q, a)
4✔
47
        end
48
end
49

50
-- color_to_hsv(c)
51
-- Takes in a normal color and returns a table with the HSV values.
52
local function color_to_hsv(c)
53
        local r = c[1]
16✔
54
        local g = c[2]
16✔
55
        local b = c[3]
16✔
56
        local a = c[4] or 1
16✔
57
        local h, s, v
58

59
        local min = math.min(r, g, b)
16✔
60
        local max = math.max(r, g, b)
16✔
61
        v = max
16✔
62

63
        local delta = max - min
16✔
64

65
        -- black, nothing else is really possible here.
66
        if min == 0 and max == 0 then
16✔
UNCOV
67
                return { 0, 0, 0, a }
×
68
        end
69

70
        if max ~= 0 then
16✔
71
                s = delta / max
16✔
72
        else
73
                -- r = g = b = 0 s = 0, v is undefined
74
                s = 0
×
75
                h = -1
×
UNCOV
76
                return { h, s, v, 1 }
×
77
        end
78

79
        -- Prevent division by zero.
80
        if delta == 0 then
16✔
81
                delta = constants.DBL_EPSILON
1✔
82
        end
83

84
        if r == max then
16✔
85
                h = ( g - b ) / delta     -- yellow/magenta
9✔
86
        elseif g == max then
7✔
87
                h = 2 + ( b - r ) / delta -- cyan/yellow
4✔
88
        else
89
                h = 4 + ( r - g ) / delta -- magenta/cyan
3✔
90
        end
91

92
        h = h / 6 -- normalize from segment 0..5
16✔
93

94
        if h < 0 then
16✔
95
                h = h + 1
6✔
96
        end
97

98
        return { h, s, v, a }
16✔
99
end
100

101
--- The public constructor.
102
-- @param x Can be of three types: </br>
103
-- number red component 0-1
104
-- table {r, g, b, a}
105
-- nil for {0,0,0,0}
106
-- @tparam number g Green component 0-1
107
-- @tparam number b Blue component 0-1
108
-- @tparam number a Alpha component 0-1
109
-- @treturn color out
110
function color.new(r, g, b, a)
1✔
111
        -- number, number, number, number
112
        if r and g and b and a then
18✔
113
                precond.typeof(r, "number", "new: Wrong argument type for r")
12✔
114
                precond.typeof(g, "number", "new: Wrong argument type for g")
12✔
115
                precond.typeof(b, "number", "new: Wrong argument type for b")
12✔
116
                precond.typeof(a, "number", "new: Wrong argument type for a")
12✔
117

118
                return new(r, g, b, a)
12✔
119

120
        -- {r, g, b, a}
121
        elseif type(r) == "table" then
6✔
122
                local rr, gg, bb, aa = r[1], r[2], r[3], r[4]
×
123
                precond.typeof(rr, "number", "new: Wrong argument type for r")
×
124
                precond.typeof(gg, "number", "new: Wrong argument type for g")
×
125
                precond.typeof(bb, "number", "new: Wrong argument type for b")
×
UNCOV
126
                precond.typeof(aa, "number", "new: Wrong argument type for a")
×
127

UNCOV
128
                return new(rr, gg, bb, aa)
×
129
        end
130

131
        return new(0, 0, 0, 0)
6✔
132
end
133

134
--- Convert hue,saturation,value table to color object.
135
-- @tparam table hsva {hue 0-1, saturation 0-1, value 0-1, alpha 0-1}
136
-- @treturn color out
137
color.hsv_to_color_table = hsv_to_color
1✔
138

139
--- Convert color to hue,saturation,value table
140
-- @tparam color in
141
-- @treturn table hsva {hue 0-1, saturation 0-1, value 0-1, alpha 0-1}
142
color.color_to_hsv_table = color_to_hsv
1✔
143

144
--- Convert hue,saturation,value to color object.
145
-- @tparam number h hue 0-1
146
-- @tparam number s saturation 0-1
147
-- @tparam number v value 0-1
148
-- @treturn color out
149
function color.from_hsv(h, s, v)
1✔
150
        return hsv_to_color { h, s, v }
1✔
151
end
152

153
--- Convert hue,saturation,value to color object.
154
-- @tparam number h hue 0-1
155
-- @tparam number s saturation 0-1
156
-- @tparam number v value 0-1
157
-- @tparam number a alpha 0-1
158
-- @treturn color out
159
function color.from_hsva(h, s, v, a)
1✔
160
        return hsv_to_color { h, s, v, a }
1✔
161
end
162

163
--- Invert a color.
164
-- @tparam color to invert
165
-- @treturn color out
166
function color.invert(c)
1✔
167
        return new(1 - c[1], 1 - c[2], 1 - c[3], c[4])
3✔
168
end
169

170
--- Lighten a color by a component-wise fixed amount (alpha unchanged)
171
-- @tparam color to lighten
172
-- @tparam number amount to increase each component by, 0-1 scale
173
-- @treturn color out
174
function color.lighten(c, v)
1✔
175
        return new(
4✔
176
                utils.clamp(c[1] + v, 0, 1),
2✔
177
                utils.clamp(c[2] + v, 0, 1),
2✔
178
                utils.clamp(c[3] + v, 0, 1),
2✔
179
                c[4]
180
        )
2✔
181
end
182

183
--- Interpolate between two colors.
184
-- @tparam color at start
185
-- @tparam color at end
186
-- @tparam number s in 0-1 progress between the two colors
187
-- @treturn color out
188
function color.lerp(a, b, s)
1✔
189
        return a + s * (b - a)
3✔
190
end
191

192
--- Unpack a color into individual components in 0-1.
193
-- @tparam color to unpack
194
-- @treturn number r in 0-1
195
-- @treturn number g in 0-1
196
-- @treturn number b in 0-1
197
-- @treturn number a in 0-1
198
function color.unpack(c)
1✔
199
        return c[1], c[2], c[3], c[4]
1✔
200
end
201

202
--- Unpack a color into individual components in 0-255.
203
-- @tparam color to unpack
204
-- @treturn number r in 0-255
205
-- @treturn number g in 0-255
206
-- @treturn number b in 0-255
207
-- @treturn number a in 0-255
208
function color.as_255(c)
1✔
209
        return c[1] * 255, c[2] * 255, c[3] * 255, c[4] * 255
1✔
210
end
211

212
--- Darken a color by a component-wise fixed amount (alpha unchanged)
213
-- @tparam color to darken
214
-- @tparam number amount to decrease each component by, 0-1 scale
215
-- @treturn color out
216
function color.darken(c, v)
1✔
217
        return new(
4✔
218
                utils.clamp(c[1] - v, 0, 1),
2✔
219
                utils.clamp(c[2] - v, 0, 1),
2✔
220
                utils.clamp(c[3] - v, 0, 1),
2✔
221
                c[4]
222
        )
2✔
223
end
224

225
--- Multiply a color's components by a value (alpha unchanged)
226
-- @tparam color to multiply
227
-- @tparam number to multiply each component by
228
-- @treturn color out
229
function color.multiply(c, v)
1✔
230
        local t = color.new()
2✔
231
        for i = 1, 3 do
8✔
232
                t[i] = c[i] * v
6✔
233
        end
234

235
        t[4] = c[4]
2✔
236
        return t
2✔
237
end
238

239
-- directly set alpha channel
240
-- @tparam color to alter
241
-- @tparam number new alpha 0-1
242
-- @treturn color out
243
function color.alpha(c, v)
1✔
244
        local t = color.new()
1✔
245
        for i = 1, 3 do
4✔
246
                t[i] = c[i]
3✔
247
        end
248

249
        t[4] = v
1✔
250
        return t
1✔
251
end
252

253
--- Multiply a color's alpha by a value
254
-- @tparam color to multiply
255
-- @tparam number to multiply alpha by
256
-- @treturn color out
257
function color.opacity(c, v)
1✔
258
        local t = color.new()
3✔
259
        for i = 1, 3 do
12✔
260
                t[i] = c[i]
9✔
261
        end
262

263
        t[4] = c[4] * v
3✔
264
        return t
3✔
265
end
266

267
--- Set a color's hue (saturation, value, alpha unchanged)
268
-- @tparam color to alter
269
-- @tparam hue to set 0-1
270
-- @treturn color out
271
function color.hue(col, hue)
1✔
272
        local c = color_to_hsv(col)
1✔
273
        c[1] = (hue + 1) % 1
1✔
274
        return hsv_to_color(c)
1✔
275
end
276

277
--- Set a color's saturation (hue, value, alpha unchanged)
278
-- @tparam color to alter
279
-- @tparam saturation to set 0-1
280
-- @treturn color out
281
function color.saturation(col, percent)
1✔
282
        local c = color_to_hsv(col)
1✔
283
        c[2] = utils.clamp(percent, 0, 1)
1✔
284
        return hsv_to_color(c)
1✔
285
end
286

287
--- Set a color's value (saturation, hue, alpha unchanged)
288
-- @tparam color to alter
289
-- @tparam value to set 0-1
290
-- @treturn color out
291
function color.value(col, percent)
1✔
292
        local c = color_to_hsv(col)
1✔
293
        c[3] = utils.clamp(percent, 0, 1)
1✔
294
        return hsv_to_color(c)
1✔
295
end
296

297
-- https://en.wikipedia.org/wiki/SRGB#From_sRGB_to_CIE_XYZ
298
function color.gamma_to_linear(r, g, b, a)
1✔
299
        local function convert(c)
300
                if c > 1.0 then
3✔
301
                        return 1.0
×
302
                elseif c < 0.0 then
3✔
303
                        return 0.0
×
304
                elseif c <= 0.04045 then
3✔
UNCOV
305
                        return c / 12.92
×
306
                else
307
                        return math.pow((c + 0.055) / 1.055, 2.4)
3✔
308
                end
309
        end
310

311
        if type(r) == "table" then
1✔
312
                local c = {}
1✔
313
                for i = 1, 3 do
4✔
314
                        c[i] = convert(r[i])
3✔
315
                end
316

317
                c[4] = r[4]
1✔
318
                return c
1✔
319
        else
UNCOV
320
                return convert(r), convert(g), convert(b), a or 1
×
321
        end
322
end
323

324
-- https://en.wikipedia.org/wiki/SRGB#From_CIE_XYZ_to_sRGB
325
function color.linear_to_gamma(r, g, b, a)
1✔
326
        local function convert(c)
327
                if c > 1.0 then
3✔
328
                        return 1.0
×
329
                elseif c < 0.0 then
3✔
330
                        return 0.0
×
331
                elseif c < 0.0031308 then
3✔
UNCOV
332
                        return c * 12.92
×
333
                else
334
                        return 1.055 * math.pow(c, 0.41666) - 0.055
3✔
335
                end
336
        end
337

338
        if type(r) == "table" then
1✔
339
                local c = {}
1✔
340
                for i = 1, 3 do
4✔
341
                        c[i] = convert(r[i])
3✔
342
                end
343

344
                c[4] = r[4]
1✔
345
                return c
1✔
346
        else
UNCOV
347
                return convert(r), convert(g), convert(b), a or 1
×
348
        end
349
end
350

351
--- Check if color is valid
352
-- @tparam color to test
353
-- @treturn boolean is color
354
function color.is_color(a)
1✔
355
        if type(a) ~= "table" then
8✔
UNCOV
356
                return false
×
357
        end
358

359
        for i = 1, 4 do
40✔
360
                if type(a[i]) ~= "number" then
32✔
UNCOV
361
                        return false
×
362
                end
363
        end
364

365
        return true
8✔
366
end
367

368
--- Return a formatted string.
369
-- @tparam color a color to be turned into a string
370
-- @treturn string formatted
371
function color.to_string(a)
1✔
UNCOV
372
        return string.format("[ %3.0f, %3.0f, %3.0f, %3.0f ]", a[1], a[2], a[3], a[4])
×
373
end
374

375
color_mt.__index = color
1✔
376
color_mt.__tostring = color.to_string
1✔
377

378
function color_mt.__call(_, r, g, b, a)
1✔
379
        return color.new(r, g, b, a)
12✔
380
end
381

382
function color_mt.__add(a, b)
1✔
383
        return new(a[1] + b[1], a[2] + b[2], a[3] + b[3], a[4] + b[4])
4✔
384
end
385

386
function color_mt.__sub(a, b)
1✔
387
        return new(a[1] - b[1], a[2] - b[2], a[3] - b[3], a[4] - b[4])
4✔
388
end
389

390
function color_mt.__mul(a, b)
1✔
391
        if type(a) == "number" then
4✔
392
                return new(a * b[1], a * b[2], a * b[3], a * b[4])
3✔
393
        elseif type(b) == "number" then
1✔
394
                return new(b * a[1], b * a[2], b * a[3], b * a[4])
1✔
395
        else
UNCOV
396
                return new(a[1] * b[1], a[2] * b[2], a[3] * b[3], a[4] * b[4])
×
397
        end
398
end
399

400
return setmetatable({}, color_mt)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc