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

excessive / cpml / 1

21 Apr 2022 05:46PM UTC coverage: 54.321% (+0.7%) from 53.574%
1

push

github

web-flow
Merge pull request #76 from xiejiangzhi/xjz

Add Vec3.angle_to

23 of 23 new or added lines in 2 files covered. (100.0%)

130 existing lines in 7 files now uncovered.

5424 of 9985 relevant lines covered (54.32%)

290.75 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('%.[^%.]+$', '') .. "."
7✔
5
local utils    = require(modules .. "utils")
7✔
6
local precond  = require(modules .. "_private_precond")
7✔
7
local color    = {}
7✔
8
local color_mt = {}
7✔
9

7✔
10
local function new(r, g, b, a)
11
        local c = { r, g, b, a }
12
        c._c = c
378✔
13
        return setmetatable(c, color)
378✔
14
end
378✔
15

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

119✔
28
        if s == 0 then
29
                return new(v, v, v, a)
119✔
30
        end
21✔
31

32
        h = hsv[1] / 60
33

98✔
34
        i = math.floor(h)
35
        f = h - i
98✔
36
        p = v * (1-s)
98✔
37
        q = v * (1-s*f)
98✔
38
        t = v * (1-s*(1-f))
98✔
39

98✔
40
        if     i == 0 then return new(v, t, p, a)
41
        elseif i == 1 then return new(q, v, p, a)
98✔
42
        elseif i == 2 then return new(p, v, t, a)
84✔
43
        elseif i == 3 then return new(p, q, v, a)
70✔
44
        elseif i == 4 then return new(t, p, v, a)
63✔
45
        else               return new(v, p, q, a)
42✔
46
        end
28✔
47
end
48

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

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

112✔
62
        local delta = max - min
63

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

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

78
        if r == max then
79
                h = ( g - b ) / delta     -- yellow/magenta
80
        elseif g == max then
112✔
81
                h = 2 + ( b - r ) / delta -- cyan/yellow
7✔
82
        else
83
                h = 4 + ( r - g ) / delta -- magenta/cyan
84
        end
112✔
85

63✔
86
        h = h * 60 -- degrees
49✔
87

28✔
88
        if h < 0 then
89
                h = h + 360
21✔
90
        end
91

92
        return { h, s, v, a }
112✔
93
end
94

112✔
95
--- The public constructor.
42✔
96
-- @param x Can be of three types: </br>
97
-- number red component 0-255
98
-- table {r, g, b, a}
112✔
99
-- nil for {0,0,0,0}
100
-- @tparam number g Green component 0-255
101
-- @tparam number b Blue component 0-255
102
-- @tparam number a Alpha component 0-255
103
-- @treturn color out
104
function color.new(r, g, b, a)
105
        -- number, number, number, number
106
        if r and g and b and a then
107
                precond.typeof(r, "number", "new: Wrong argument type for r")
108
                precond.typeof(g, "number", "new: Wrong argument type for g")
109
                precond.typeof(b, "number", "new: Wrong argument type for b")
110
                precond.typeof(a, "number", "new: Wrong argument type for a")
7✔
111

112
                return new(r, g, b, a)
126✔
113

84✔
114
        -- {r, g, b, a}
84✔
115
        elseif type(r) == "table" then
84✔
116
                local rr, gg, bb, aa = r[1], r[2], r[3], r[4]
84✔
117
                precond.typeof(rr, "number", "new: Wrong argument type for r")
118
                precond.typeof(gg, "number", "new: Wrong argument type for g")
84✔
119
                precond.typeof(bb, "number", "new: Wrong argument type for b")
120
                precond.typeof(aa, "number", "new: Wrong argument type for a")
121

42✔
UNCOV
122
                return new(rr, gg, bb, aa)
×
UNCOV
123
        end
×
124

×
UNCOV
125
        return new(0, 0, 0, 0)
×
UNCOV
126
end
×
127

UNCOV
128
--- Convert hue,saturation,value table to color object.
×
129
-- @tparam table hsva {hue 0-359, saturation 0-1, value 0-1, alpha 0-255}
130
-- @treturn color out
131
color.hsv_to_color_table = hsv_to_color
42✔
132

133
--- Convert color to hue,saturation,value table
134
-- @tparam color in
135
-- @treturn table hsva {hue 0-359, saturation 0-1, value 0-1, alpha 0-255}
136
color.color_to_hsv_table = color_to_hsv
137

7✔
138
--- Convert hue,saturation,value to color object.
139
-- @tparam number h hue 0-359
140
-- @tparam number s saturation 0-1
141
-- @tparam number v value 0-1
142
-- @treturn color out
7✔
143
function color.from_hsv(h, s, v)
144
        return hsv_to_color { h, s, v }
145
end
146

147
--- Convert hue,saturation,value to color object.
148
-- @tparam number h hue 0-359
149
-- @tparam number s saturation 0-1
7✔
150
-- @tparam number v value 0-1
7✔
151
-- @tparam number a alpha 0-255
152
-- @treturn color out
153
function color.from_hsva(h, s, v, a)
154
        return hsv_to_color { h, s, v, a }
155
end
156

157
--- Invert a color.
158
-- @tparam color to invert
159
-- @treturn color out
7✔
160
function color.invert(c)
7✔
161
        return new(255 - c[1], 255 - c[2], 255 - c[3], c[4])
162
end
163

164
--- Lighten a color by a component-wise fixed amount (alpha unchanged)
165
-- @tparam color to lighten
166
-- @tparam number amount to increase each component by, 0-255 scale
7✔
167
-- @treturn color out
21✔
168
function color.lighten(c, v)
169
        return new(
170
                utils.clamp(c[1] + v * 255, 0, 255),
171
                utils.clamp(c[2] + v * 255, 0, 255),
172
                utils.clamp(c[3] + v * 255, 0, 255),
173
                c[4]
174
        )
7✔
175
end
28✔
176

14✔
177
function color.lerp(a, b, s)
14✔
178
        return a + s * (b - a)
14✔
179
end
180

14✔
181
--- Darken a color by a component-wise fixed amount (alpha unchanged)
182
-- @tparam color to darken
183
-- @tparam number amount to decrease each component by, 0-255 scale
184
-- @treturn color out
185
function color.darken(c, v)
186
        return new(
187
                utils.clamp(c[1] - v * 255, 0, 255),
188
                utils.clamp(c[2] - v * 255, 0, 255),
7✔
189
                utils.clamp(c[3] - v * 255, 0, 255),
21✔
190
                c[4]
191
        )
192
end
193

194
--- Multiply a color's components by a value (alpha unchanged)
195
-- @tparam color to multiply
196
-- @tparam number to multiply each component by
197
-- @treturn color out
198
function color.multiply(c, v)
7✔
199
        local t = color.new()
7✔
200
        for i = 1, 3 do
201
                t[i] = c[i] * v
202
        end
203

204
        t[4] = c[4]
205
        return t
206
end
207

208
-- directly set alpha channel
7✔
209
-- @tparam color to alter
7✔
210
-- @tparam number new alpha 0-255
211
-- @treturn color out
212
function color.alpha(c, v)
213
        local t = color.new()
214
        for i = 1, 3 do
215
                t[i] = c[i]
216
        end
7✔
217

28✔
218
        t[4] = v * 255
14✔
219
        return t
14✔
220
end
14✔
221

222
--- Multiply a color's alpha by a value
14✔
223
-- @tparam color to multiply
224
-- @tparam number to multiply alpha by
225
-- @treturn color out
226
function color.opacity(c, v)
227
        local t = color.new()
228
        for i = 1, 3 do
229
                t[i] = c[i]
7✔
230
        end
14✔
231

56✔
232
        t[4] = c[4] * v
42✔
233
        return t
234
end
235

14✔
236
--- Set a color's hue (saturation, value, alpha unchanged)
14✔
237
-- @tparam color to alter
238
-- @tparam hue to set 0-359
239
-- @treturn color out
240
function color.hue(col, hue)
241
        local c = color_to_hsv(col)
242
        c[1] = (hue + 360) % 360
243
        return hsv_to_color(c)
7✔
244
end
7✔
245

28✔
246
--- Set a color's saturation (hue, value, alpha unchanged)
21✔
247
-- @tparam color to alter
248
-- @tparam hue to set 0-359
249
-- @treturn color out
7✔
250
function color.saturation(col, percent)
7✔
251
        local c = color_to_hsv(col)
252
        c[2] = utils.clamp(percent, 0, 1)
253
        return hsv_to_color(c)
254
end
255

256
--- Set a color's value (saturation, hue, alpha unchanged)
257
-- @tparam color to alter
7✔
258
-- @tparam hue to set 0-359
21✔
259
-- @treturn color out
84✔
260
function color.value(col, percent)
63✔
261
        local c = color_to_hsv(col)
262
        c[3] = utils.clamp(percent, 0, 1)
263
        return hsv_to_color(c)
21✔
264
end
21✔
265

266
-- http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
267
function color.gamma_to_linear(r, g, b, a)
268
        local function convert(c)
269
                if c > 1.0 then
270
                        return 1.0
271
                elseif c < 0.0 then
7✔
272
                        return 0.0
7✔
273
                elseif c <= 0.04045 then
7✔
274
                        return c / 12.92
7✔
275
                else
276
                        return math.pow((c + 0.055) / 1.055, 2.4)
277
                end
278
        end
279

280
        if type(r) == "table" then
281
                local c = {}
7✔
282
                for i = 1, 3 do
7✔
283
                        c[i] = convert(r[i] / 255) * 255
7✔
284
                end
7✔
285

286
                c[4] = convert(r[4] / 255) * 255
287
                return c
288
        else
289
                return convert(r / 255) * 255, convert(g / 255) * 255, convert(b / 255) * 255, a or 255
290
        end
291
end
7✔
292

7✔
293
-- http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29
7✔
294
function color.linear_to_gamma(r, g, b, a)
7✔
295
        local function convert(c)
296
                if c > 1.0 then
297
                        return 1.0
298
                elseif c < 0.0 then
7✔
299
                        return 0.0
300
                elseif c < 0.0031308 then
21✔
UNCOV
301
                        return c * 12.92
×
302
                else
21✔
UNCOV
303
                        return 1.055 * math.pow(c, 0.41666) - 0.055
×
304
                end
21✔
UNCOV
305
        end
×
306

307
        if type(r) == "table" then
21✔
308
                local c = {}
309
                for i = 1, 3 do
310
                        c[i] = convert(r[i] / 255) * 255
311
                end
7✔
312

7✔
313
                c[4] = convert(r[4] / 255) * 255
28✔
314
                return c
21✔
315
        else
316
                return convert(r / 255) * 255, convert(g / 255) * 255, convert(b / 255) * 255, a or 255
317
        end
7✔
318
end
7✔
319

UNCOV
320
--- Check if color is valid
×
321
-- @tparam color to test
322
-- @treturn boolean is color
323
function color.is_color(a)
324
        if type(a) ~= "table" then
325
                return false
7✔
326
        end
327

21✔
328
        for i = 1, 4 do
×
329
                if type(a[i]) ~= "number" then
21✔
UNCOV
330
                        return false
×
331
                end
21✔
UNCOV
332
        end
×
333

334
        return true
21✔
335
end
336

337
--- Return a formatted string.
338
-- @tparam color a color to be turned into a string
7✔
339
-- @treturn string formatted
7✔
340
function color.to_string(a)
28✔
341
        return string.format("[ %3.0f, %3.0f, %3.0f, %3.0f ]", a[1], a[2], a[3], a[4])
21✔
342
end
343

344
function color_mt.__index(t, k)
7✔
345
        if type(t) == "cdata" then
7✔
346
                if type(k) == "number" then
UNCOV
347
                        return t._c[k-1]
×
348
                end
349
        end
350

351
        return rawget(color, k)
352
end
353

354
function color_mt.__newindex(t, k, v)
7✔
355
        if type(t) == "cdata" then
56✔
356
                if type(k) == "number" then
×
357
                        t._c[k-1] = v
358
                end
359
        end
280✔
360
end
224✔
UNCOV
361

×
362
color_mt.__tostring = color.to_string
363

364
function color_mt.__call(_, r, g, b, a)
365
        return color.new(r, g, b, a)
56✔
366
end
367

368
function color_mt.__add(a, b)
369
        return new(a[1] + b[1], a[2] + b[2], a[3] + b[3], a[4] + b[4])
370
end
371

7✔
372
function color_mt.__sub(a, b)
×
373
        return new(a[1] - b[1], a[2] - b[2], a[3] - b[3], a[4] - b[4])
374
end
375

7✔
376
function color_mt.__mul(a, b)
7✔
377
        if type(a) == "number" then
378
                return new(a * b[1], a * b[2], a * b[3], a * b[4])
7✔
379
        elseif type(b) == "number" then
84✔
380
                return new(b * a[1], b * a[2], b * a[3], b * a[4])
381
        else
382
                return new(a[1] * b[1], a[2] * b[2], a[3] * b[3], a[4] * b[4])
7✔
383
        end
28✔
384
end
385

386
return setmetatable({}, color_mt)
7✔
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